Make parent_class static.
authorOwen Taylor <otaylor@redhat.com>
Sun, 12 Nov 2000 03:43:24 +0000 (03:43 +0000)
committerOwen Taylor <otaylor@src.gnome.org>
Sun, 12 Nov 2000 03:43:24 +0000 (03:43 +0000)
Sun Nov  5 04:24:53 2000  Owen Taylor  <otaylor@redhat.com>

* gtk/gtkcellrenderertextpixbuf.c: Make parent_class
static.

Tue Sep 19 10:54:22 2000  Owen Taylor  <otaylor@redhat.com>

* gtk/gtkimcontext*.[ch] gtk/gtkimmulticontext.[ch]
gtk/gtktextlayout.[ch] gtk/gtktextview.c gtk/gtkentry.c:
Add support for positioning the cursor within the preedit string.

Mon Sep 18 23:56:32 2000  Owen Taylor  <otaylor@redhat.com>

* gtk/gtktextview.c: Check for bindings after passing
events to im context filter.

Mon Sep 18 11:50:51 2000  Owen Taylor  <otaylor@redhat.com>

* gtk/gtktextlayout.c (add_preedit_attrs): Handle
empty attribute lists properly.

Sun Sep 17 10:08:16 2000  Owen Taylor  <otaylor@redhat.com>

* gtk/queryimmodules.c (main): Return non-zero exit
status if errors were encountered querying any
modules.

Sat Sep 16 14:01:52 2000  Owen Taylor  <otaylor@redhat.com>

* gtk/gtk.h: include gtkmodule.h gtkoldeditable.h,
don't include gtkthemes.h.

* gtk/testgtk.c gtk/testtext.c: Set environment variables
to point

* gtk/Makefile.am: Add new .c and .h files, build
gtk-query-immodules and use it to create a gtk.immodules
file for use of test programs.

* gtk/gtkpreview.c: remove extra blank line.

Sat Sep 16 13:21:04 2000  Owen Taylor  <otaylor@redhat.com>

* gtk/gtkimcontextsimple.c (gtk_im_context_simple_add_table):
Add the ability to add extra tables beyond the default
one, and also the ability to have compose sequences
that are prefixes of other compose sequences.

* gtk/gtkimcontextsimple.c: Export a preedit string which
consists of possible candidates for keystrokes that have
been entered but not yet committed.

* gtk/gtkimcontext.[ch] gtk/immulticontext.[ch]
gtk/gtkimcontextsimple.[ch]: add gtk_im_context_reset()

* gtk/gtkmulticontext.[ch] (gtk_im_multicontext_append_menuitems):
Add a function to add input-method switching menu items
to a menu.

* gtk/gtkimmulticontext.[ch]: Properly handly set_client_window
when switching input methods.

* gtk/gtkimcontextsimple.[ch]: Change the format of
the compose table to allow compose tables of different
lengths / sequence.

Sat Sep 16 13:05:48 2000  Owen Taylor  <otaylor@redhat.com>

* gtk/gtkimmodule.[ch]: Support routines for loading
GtkIMContext implementations dynamically at runtime.

* gtk/queryimmodules.c: Program to query the available
input modules and write the results into a file.

* gtk/gtkrc.[ch] (gtk_rc_get_im_module_file): Add
extra config options "im_module_file" (cache file for
input method modules), and "im_module_path" - path
to look for modules when generating cache file.

This doesn't scale.

Sat Sep 16 13:09:06 2000  Owen Taylor  <otaylor@redhat.com>

* gtk/gtkthemes.[ch] gtk/gtkmodule.[ch]: Move most of the
generic code from gtkthemes into a new abstraction
GtkModule which has the logic for implementing
a loadable module which implements a number of
GObject types.

Sat Sep 16 13:07:13 2000  Owen Taylor  <otaylor@redhat.com>

        * gtk/gtkeditable.[ch]: Convert GtkEditable from
a class into an interface

* gtk/gtkoldeditable.[ch]: Move the old editable
implementation into here, so legacy widgets can
still rely on the implemenation. GtkOldEditable
exports GtkEditable. Make selection handling
code use new text conversion functions (and
handle UTF-8 as a side-effect). Use GtkClipboard
for CLIPBOARD.

* gtk/gtktext.[ch] gtk/gtkcombo.c gtk/gtkspinbutton.c:
Adopt to match above changes.

* gtk/gtkentry.[ch]: Implement GtkEditable directly,
avoid GtkOldEditable implementation. Restructure
        to reduce number of places that modify state directly.
Move to GtkBindingSet. Display the preedit string.
Queue recomputation of PangoLayout and scroll position
to improve effiency of doing complex changes naively.
Add a menu with cut/copy/paste and input method selection.

Thu Sep 14 22:11:05 2000  Owen Taylor  <otaylor@redhat.com>

* gtk/gtktextlayout.[ch]: Add gtk_text_layout_set_preedit_string()
to set preedit string and attributes; display preedit string by
inserting string and attributes at cursor when creating the
GtkTextLineDisplay.

* gtk/gtktextlayout.c: Move all conversions between byte
positions in PangoLayout and GtkTextIter into new functions
line_display_iter_to_index/index_to_iter that properly
handle the preedit string.

* gtk/gtktextmark.[ch]: Restore gtk_text_mark_get_name, modify
it to return const char * (eventually will end up
as GCONST char *, most likely.)

* gtk/gtktextview.[ch]: Handle the preedit string, call
gtk_im_context_reset() as necessary, add a menu to switch
input methods.

* gtk/gtktextlayout.[ch]: Remove useless
gtk_text_layout_get_log_attrs() function.

36 files changed:
gtk/.cvsignore
gtk/Makefile.am
gtk/gtk.h
gtk/gtkcellrenderertextpixbuf.c
gtk/gtkcombo.c
gtk/gtkeditable.c
gtk/gtkeditable.h
gtk/gtkentry.c
gtk/gtkentry.h
gtk/gtkimcontext.c
gtk/gtkimcontext.h
gtk/gtkimcontextsimple.c
gtk/gtkimcontextsimple.h
gtk/gtkimmodule.c [new file with mode: 0644]
gtk/gtkimmodule.h [new file with mode: 0644]
gtk/gtkimmulticontext.c
gtk/gtkimmulticontext.h
gtk/gtkoldeditable.c [new file with mode: 0644]
gtk/gtkoldeditable.h [new file with mode: 0644]
gtk/gtkpreview.c
gtk/gtkrc.c
gtk/gtkrc.h
gtk/gtkspinbutton.c
gtk/gtktext.c
gtk/gtktext.h
gtk/gtktextlayout.c
gtk/gtktextlayout.h
gtk/gtktextview.c
gtk/gtktextview.h
gtk/gtkthemes.c
gtk/gtkthemes.h
gtk/queryimmodules.c [new file with mode: 0644]
gtk/testgtk.c
gtk/testtext.c
tests/testgtk.c
tests/testtext.c

index 1a313c90c280cb9ec3d31d278187e592a0d240e0..d93b49fe1137d07e22305bd48550fffedb11dc84 100644 (file)
@@ -19,6 +19,7 @@ testtree
 gtkcompat.h
 testthreads
 libgtk.la
+gtkfeatures.h
 gtkmarshal.h
 gtktypebuiltins.h
 gtkmarshal.c
@@ -30,3 +31,5 @@ testdnd
 stamp-gtktypebuiltins.h
 stamp-gtkmarshal.h
 stamp-gtk.defs
+gtk-query-immodules-2.0
+gtk.immodules
index e05b165c066b0c4b7cec3121bea2386e08261704..060d12154cca6b783a7b357ab271fb152bc1f835 100644 (file)
@@ -104,6 +104,7 @@ gtk_public_h_sources = @STRIP_BEGIN@ \
        gtkiconfactory.h        \
        gtkimage.h              \
        gtkimcontext.h          \
+       gtkimmodule.h           \
        gtkimmulticontext.h     \
        gtkinputdialog.h        \
        gtkinvisible.h          \
@@ -124,6 +125,7 @@ gtk_public_h_sources = @STRIP_BEGIN@ \
        gtkmisc.h               \
        gtkmodelsimple.h        \
        gtknotebook.h           \
+       gtkoldeditable.h        \
        gtkobject.h             \
        gtkoptionmenu.h         \
        gtkpacker.h             \
@@ -163,7 +165,6 @@ gtk_public_h_sources = @STRIP_BEGIN@ \
        gtktexttagtable.h       \
        gtktextview.h           \
        gtktext.h               \
-       gtkthemes.h             \
        gtktipsquery.h          \
        gtktogglebutton.h       \
        gtktoolbar.h            \
@@ -198,6 +199,7 @@ gtk_private_h_sources = @STRIP_BEGIN@ \
        gtktextiterprivate.h    \
        gtktextmarkprivate.h    \
        gtktexttagprivate.h     \
+       gtkthemes.h             \
        gtktreeprivate.h        \
 @STRIP_END@
 # GTK+ C sources to build the library from
@@ -257,6 +259,7 @@ gtk_c_sources = @STRIP_BEGIN@   \
        gtkimcontext.c          \
        gtkimcontextsimple.c    \
        gtkimcontextsimple.h    \
+       gtkimmodule.c           \
        gtkimmulticontext.c     \
        gtkinputdialog.c        \
        gtkintl.h               \
@@ -279,6 +282,7 @@ gtk_c_sources = @STRIP_BEGIN@   \
        gtkmodelsimple.c        \
        gtknotebook.c           \
        gtkobject.c             \
+       gtkoldeditable.c        \
        gtkoptionmenu.c         \
        gtkpacker.c             \
        gtkpaned.c              \
@@ -543,11 +547,9 @@ install-data-local:
 uninstall-local:
        rm -f $(DESTDIR)$(datadir)/themes/Default/gtk-2.0/gtkrc
 
-#
-# test programs, not to be installed
-#
-noinst_PROGRAMS = testgtk testcalendar testinput testselection testrgb testdnd testtext simple treestoretest testtextbuffer # testthreads
-DEPS = @gtktargetlib@ $(top_builddir)/gdk-pixbuf/libgdk_pixbuf-1.3.la  $(top_builddir)/gdk/@gdktargetlib@
+DEPS = @gtktargetlib@ $(top_builddir)/gdk-pixbuf/libgdk_pixbuf-1.3.la $(top_builddir)/gdk/@gdktargetlib@
+TEST_DEPS = $(DEPS) gtk.immodules
+
 LDADDS = @STRIP_BEGIN@ \
        @gtktargetlib@                                  \
        $(top_builddir)/gdk-pixbuf/libgdk_pixbuf-1.3.la \
@@ -561,25 +563,44 @@ LDADDS = @STRIP_BEGIN@ \
        -lm                                             \
 @STRIP_END@
 
-testgtk_DEPENDENCIES = $(DEPS)
-testcalendar_DEPENDENCIES = $(DEPS)
-testinput_DEPENDENCIES = $(DEPS)
-testselection_DEPENDENCIES = $(DEPS)
-testrgb_DEPENDENCIES = $(DEPS)
-testtext_DEPENDENCIES = $(DEPS)
-testtextbuffer_DEPENDENCIES = $(DEPS)
-treestoretest_DEPENDENCIES = $(DEPS)
-testdnd_DEPENDENCIES = $(DEPS)
-simple_DEPENDENCIES = $(DEPS)
-#testthreads_DEPENDENCIES = $(DEPS)
+#
+# Installed tools
+#
+bin_PROGRAMS = gtk-query-immodules-2.0
+
+gtk_query_immodules_2_0_DEPENDENCIES = $(DEPS)
+gtk_query_immodules_2_0_LDADD = $(LDADDS)
+
+gtk_query_immodules_2_0_SOURCES = queryimmodules.c
+
+gtk.immodules: gtk-query-immodules-2.0
+       ./gtk-query-immodules-2.0 ../modules/input/.libs/*.so > gtk.immodules
+
+#
+# test programs, not to be installed
+#
+noinst_PROGRAMS = testgtk testcalendar testinput testselection testrgb testdnd testtext simple treestoretest testtextbuffer # testthreads
+
+testcalendar_DEPENDENCIES = $(TEST_DEPS)
+testgtk_DEPENDENCIES = $(TEST_DEPS)
+testinput_DEPENDENCIES = $(TEST_DEPS)
+testrgb_DEPENDENCIES = $(TEST_DEPS)
+testselection_DEPENDENCIES = $(TEST_DEPS)
+testtext_DEPENDENCIES = $(TEST_DEPS)
+testtextbuffer_DEPENDENCIES = $(TEST_DEPS)
+treestoretest_DEPENDENCIES = $(TEST_DEPS)
+testdnd_DEPENDENCIES = $(TEST_DEPS)
+simple_DEPENDENCIES = $(TEST_DEPS)
+#testthreads_DEPENDENCIES = $(TEST_DEPS)
+
 testcalendar_LDADD = $(LDADDS)
 testgtk_LDADD = $(LDADDS)
 testinput_LDADD = $(LDADDS)
+testrgb_LDADD = $(LDADDS)
 testselection_LDADD = $(LDADDS)
 testtext_LDADD = $(LDADDS)
-treestoretest_LDADD = $(LDADDS)
 testtextbuffer_LDADD = $(LDADDS)
-testrgb_LDADD = $(LDADDS)
+treestoretest_LDADD = $(LDADDS)
 testdnd_LDADD = $(LDADDS)
 simple_LDADD = $(LDADDS)
 #testthreads_LDADD = $(LDADDS)
index a7b3e8818caedd6561926ddb0143d097d12d0719..ecec92e466d14e883632d24332727cf153b87329 100644 (file)
--- a/gtk/gtk.h
+++ b/gtk/gtk.h
 #include <gtk/gtkmodelsimple.h>
 #include <gtk/gtknotebook.h>
 #include <gtk/gtkobject.h>
+#include <gtk/gtkoldeditable.h>
 #include <gtk/gtkoptionmenu.h>
 #include <gtk/gtkpacker.h>
 #include <gtk/gtkpaned.h>
 #include <gtk/gtktext.h>
 #include <gtk/gtktextbuffer.h>
 #include <gtk/gtktextview.h>
-#include <gtk/gtkthemes.h>
 #include <gtk/gtktipsquery.h>
 #include <gtk/gtktogglebutton.h>
 #include <gtk/gtktoolbar.h>
index d2fe42dac42a437cb73738d0adc852948bfe9284..694538a2b695c057676c2e42b6a12214cc64e226 100644 (file)
@@ -60,7 +60,7 @@ static void gtk_cell_renderer_text_pixbuf_render     (GtkCellRenderer
                                                      guint                           flags);
 
 
-GtkCellRendererTextClass *parent_class = NULL;
+static GtkCellRendererTextClass *parent_class = NULL;
 
 
 GtkType
index 03cb0faab60b0b2ba795c27fb3bb08077e66a929..dea6d8956c6a1741315bf975a136001313decae0 100644 (file)
@@ -132,6 +132,7 @@ gtk_combo_entry_key_press (GtkEntry * entry, GdkEventKey * event, GtkCombo * com
   /* completion */
   if ((event->keyval == GDK_Tab) && (event->state & GDK_MOD1_MASK)) 
     {
+      GtkEditable *editable = GTK_EDITABLE (entry);
     GCompletion * cmpl;
     gchar* prefix;
     gchar* nprefix = NULL;
@@ -145,16 +146,16 @@ gtk_combo_entry_key_press (GtkEntry * entry, GdkEventKey * event, GtkCombo * com
     cmpl = g_completion_new ((GCompletionFunc)gtk_combo_func);
     g_completion_add_items (cmpl, GTK_LIST (combo->list)->children);
 
-    pos = GTK_EDITABLE (entry)->current_pos;
-    prefix = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, pos);
+    pos = gtk_editable_get_position (editable);
+    prefix = gtk_editable_get_chars (editable, 0, pos);
 
     g_completion_complete(cmpl, prefix, &nprefix);
 
     if (nprefix && strlen (nprefix) > strlen (prefix)) 
       {
-       gtk_editable_insert_text (GTK_EDITABLE (entry), nprefix + pos, 
-                                strlen (nprefix) - strlen (prefix), &pos);
-       GTK_EDITABLE (entry)->current_pos = pos;
+       gtk_editable_insert_text (editable, nprefix + pos, 
+                                 strlen (nprefix) - strlen (prefix), &pos);
+       gtk_editable_set_position (editable, pos);
     }
 
     if (nprefix)
index 76ee618fda3394ad2e82eee8385fe1f0e28e35d2..b2ea905c332272b149ff3df7126af0ff6afbb697 100644 (file)
  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
  */
 
-#include <ctype.h>
 #include <string.h>
-#include "gdk/gdkkeysyms.h"
-#include "gdk/gdki18n.h"
+
 #include "gtkeditable.h"
-#include "gtkmain.h"
-#include "gtkselection.h"
 #include "gtksignal.h"
 
-#define MIN_EDITABLE_WIDTH  150
-#define DRAW_TIMEOUT     20
-#define INNER_BORDER     2
-
-enum {
-  CHANGED,
-  INSERT_TEXT,
-  DELETE_TEXT,
-  /* Binding actions */
-  ACTIVATE,
-  SET_EDITABLE,
-  MOVE_CURSOR,
-  MOVE_WORD,
-  MOVE_PAGE,
-  MOVE_TO_ROW,
-  MOVE_TO_COLUMN,
-  KILL_CHAR,
-  KILL_WORD,
-  KILL_LINE,
-  CUT_CLIPBOARD,
-  COPY_CLIPBOARD,
-  PASTE_CLIPBOARD,
-  LAST_SIGNAL
-};
-
-enum {
-  ARG_0,
-  ARG_TEXT_POSITION,
-  ARG_EDITABLE
-};
-
-/* values for selection info */
-
-enum {
-  TARGET_STRING,
-  TARGET_TEXT,
-  TARGET_COMPOUND_TEXT
-};
-
-static void gtk_editable_class_init          (GtkEditableClass *klass);
-static void gtk_editable_init                (GtkEditable      *editable);
-static void gtk_editable_set_arg            (GtkObject        *object,
-                                             GtkArg           *arg,
-                                             guint             arg_id);
-static void gtk_editable_get_arg            (GtkObject        *object,
-                                             GtkArg           *arg,
-                                             guint             arg_id);
-static void *gtk_editable_get_public_chars   (GtkEditable      *editable,
-                                             gint              start,
-                                             gint              end);
-static gint gtk_editable_selection_clear     (GtkWidget        *widget,
-                                            GdkEventSelection *event);
-static void gtk_editable_selection_get      (GtkWidget         *widget,
-                                            GtkSelectionData  *selection_data,
-                                            guint              info,
-                                            guint              time);
-static void gtk_editable_selection_received  (GtkWidget        *widget,
-                                             GtkSelectionData *selection_data,
-                                             guint             time);
-
-static void gtk_editable_set_selection    (GtkEditable      *editable,
-                                          gint              start,
-                                          gint              end);
-static guint32 gtk_editable_get_event_time (GtkEditable     *editable);
-
-static void gtk_editable_real_cut_clipboard   (GtkEditable     *editable);
-static void gtk_editable_real_copy_clipboard  (GtkEditable     *editable);
-static void gtk_editable_real_paste_clipboard (GtkEditable     *editable);
-static void gtk_editable_real_set_editable    (GtkEditable     *editable,
-                                              gboolean         is_editable);
-     
-static GtkWidgetClass *parent_class = NULL;
-static guint editable_signals[LAST_SIGNAL] = { 0 };
-
-static GdkAtom clipboard_atom = GDK_NONE;
-
 GtkType
 gtk_editable_get_type (void)
 {
@@ -116,331 +36,32 @@ gtk_editable_get_type (void)
 
   if (!editable_type)
     {
-      static const GtkTypeInfo editable_info =
+      static const GTypeInfo editable_info =
       {
-       "GtkEditable",
-       sizeof (GtkEditable),
-       sizeof (GtkEditableClass),
-       (GtkClassInitFunc) gtk_editable_class_init,
-       (GtkObjectInitFunc) gtk_editable_init,
-       /* reserved_1 */ NULL,
-       /* reserved_2 */ NULL,
-        (GtkClassInitFunc) NULL,
+       sizeof (GtkEditableClass),  /* class_size */
+       NULL,                       /* base_init */
+       NULL,                       /* base_finalize */
       };
 
-      editable_type = gtk_type_unique (GTK_TYPE_WIDGET, &editable_info);
+      editable_type = g_type_register_static (G_TYPE_INTERFACE, "GtkEditable", &editable_info, 0);
     }
 
   return editable_type;
 }
 
-static void
-gtk_editable_class_init (GtkEditableClass *class)
-{
-  GtkObjectClass *object_class;
-  GtkWidgetClass *widget_class;
-
-  object_class = (GtkObjectClass*) class;
-  widget_class = (GtkWidgetClass*) class;
-
-  parent_class = gtk_type_class (GTK_TYPE_WIDGET);
-
-  editable_signals[CHANGED] =
-    gtk_signal_new ("changed",
-                   GTK_RUN_LAST,
-                   GTK_CLASS_TYPE (object_class),
-                   GTK_SIGNAL_OFFSET (GtkEditableClass, changed),
-                   gtk_marshal_VOID__VOID,
-                   GTK_TYPE_NONE, 0);
-
-  editable_signals[INSERT_TEXT] =
-    gtk_signal_new ("insert_text",
-                   GTK_RUN_LAST,
-                   GTK_CLASS_TYPE (object_class),
-                   GTK_SIGNAL_OFFSET (GtkEditableClass, insert_text),
-                   gtk_marshal_VOID__POINTER_INT_POINTER,
-                   GTK_TYPE_NONE,
-                   3,
-                   GTK_TYPE_STRING,
-                   GTK_TYPE_INT,
-                   GTK_TYPE_POINTER);
-
-  editable_signals[DELETE_TEXT] =
-    gtk_signal_new ("delete_text",
-                   GTK_RUN_LAST,
-                   GTK_CLASS_TYPE (object_class),
-                   GTK_SIGNAL_OFFSET (GtkEditableClass, delete_text),
-                   gtk_marshal_VOID__INT_INT,
-                   GTK_TYPE_NONE,
-                   2,
-                   GTK_TYPE_INT,
-                   GTK_TYPE_INT);                  
-
-  editable_signals[ACTIVATE] =
-    gtk_signal_new ("activate",
-                   GTK_RUN_LAST | GTK_RUN_ACTION,
-                   GTK_CLASS_TYPE (object_class),
-                   GTK_SIGNAL_OFFSET (GtkEditableClass, activate),
-                   gtk_marshal_VOID__VOID,
-                   GTK_TYPE_NONE, 0);
-  widget_class->activate_signal = editable_signals[ACTIVATE];
-
-  editable_signals[SET_EDITABLE] =
-    gtk_signal_new ("set-editable",
-                   GTK_RUN_LAST | GTK_RUN_ACTION,
-                   GTK_CLASS_TYPE (object_class),
-                   GTK_SIGNAL_OFFSET (GtkEditableClass, set_editable),
-                   gtk_marshal_VOID__BOOLEAN,
-                   GTK_TYPE_NONE, 1,
-                   GTK_TYPE_BOOL);
-
-  editable_signals[MOVE_CURSOR] =
-    gtk_signal_new ("move_cursor",
-                   GTK_RUN_LAST | GTK_RUN_ACTION,
-                   GTK_CLASS_TYPE (object_class),
-                   GTK_SIGNAL_OFFSET (GtkEditableClass, move_cursor),
-                   gtk_marshal_VOID__INT_INT,
-                   GTK_TYPE_NONE, 2, 
-                   GTK_TYPE_INT, 
-                   GTK_TYPE_INT);
-
-  editable_signals[MOVE_WORD] =
-    gtk_signal_new ("move_word",
-                   GTK_RUN_LAST | GTK_RUN_ACTION,
-                   GTK_CLASS_TYPE (object_class),
-                   GTK_SIGNAL_OFFSET (GtkEditableClass, move_word),
-                   gtk_marshal_VOID__INT,
-                   GTK_TYPE_NONE, 1, 
-                   GTK_TYPE_INT);
-
-  editable_signals[MOVE_PAGE] =
-    gtk_signal_new ("move_page",
-                   GTK_RUN_LAST | GTK_RUN_ACTION,
-                   GTK_CLASS_TYPE (object_class),
-                   GTK_SIGNAL_OFFSET (GtkEditableClass, move_page),
-                   gtk_marshal_VOID__INT_INT,
-                   GTK_TYPE_NONE, 2, 
-                   GTK_TYPE_INT, 
-                   GTK_TYPE_INT);
-
-  editable_signals[MOVE_TO_ROW] =
-    gtk_signal_new ("move_to_row",
-                   GTK_RUN_LAST | GTK_RUN_ACTION,
-                   GTK_CLASS_TYPE (object_class),
-                   GTK_SIGNAL_OFFSET (GtkEditableClass, move_to_row),
-                   gtk_marshal_VOID__INT,
-                   GTK_TYPE_NONE, 1, 
-                   GTK_TYPE_INT);
-
-  editable_signals[MOVE_TO_COLUMN] =
-    gtk_signal_new ("move_to_column",
-                   GTK_RUN_LAST | GTK_RUN_ACTION,
-                   GTK_CLASS_TYPE (object_class),
-                   GTK_SIGNAL_OFFSET (GtkEditableClass, move_to_column),
-                   gtk_marshal_VOID__INT,
-                   GTK_TYPE_NONE, 1, 
-                   GTK_TYPE_INT);
-
-  editable_signals[KILL_CHAR] =
-    gtk_signal_new ("kill_char",
-                   GTK_RUN_LAST | GTK_RUN_ACTION,
-                   GTK_CLASS_TYPE (object_class),
-                   GTK_SIGNAL_OFFSET (GtkEditableClass, kill_char),
-                   gtk_marshal_VOID__INT,
-                   GTK_TYPE_NONE, 1, 
-                   GTK_TYPE_INT);
-
-  editable_signals[KILL_WORD] =
-    gtk_signal_new ("kill_word",
-                   GTK_RUN_LAST | GTK_RUN_ACTION,
-                   GTK_CLASS_TYPE (object_class),
-                   GTK_SIGNAL_OFFSET (GtkEditableClass, kill_word),
-                   gtk_marshal_VOID__INT,
-                   GTK_TYPE_NONE, 1, 
-                   GTK_TYPE_INT);
-
-  editable_signals[KILL_LINE] =
-    gtk_signal_new ("kill_line",
-                   GTK_RUN_LAST | GTK_RUN_ACTION,
-                   GTK_CLASS_TYPE (object_class),
-                   GTK_SIGNAL_OFFSET (GtkEditableClass, kill_line),
-                   gtk_marshal_VOID__INT,
-                   GTK_TYPE_NONE, 1, 
-                   GTK_TYPE_INT);
-
-  editable_signals[CUT_CLIPBOARD] =
-    gtk_signal_new ("cut_clipboard",
-                   GTK_RUN_LAST | GTK_RUN_ACTION,
-                   GTK_CLASS_TYPE (object_class),
-                   GTK_SIGNAL_OFFSET (GtkEditableClass, cut_clipboard),
-                   gtk_marshal_VOID__VOID,
-                   GTK_TYPE_NONE, 0);
-
-  editable_signals[COPY_CLIPBOARD] =
-    gtk_signal_new ("copy_clipboard",
-                   GTK_RUN_LAST | GTK_RUN_ACTION,
-                   GTK_CLASS_TYPE (object_class),
-                   GTK_SIGNAL_OFFSET (GtkEditableClass, copy_clipboard),
-                   gtk_marshal_VOID__VOID,
-                   GTK_TYPE_NONE, 0);
-
-  editable_signals[PASTE_CLIPBOARD] =
-    gtk_signal_new ("paste_clipboard",
-                   GTK_RUN_LAST | GTK_RUN_ACTION,
-                   GTK_CLASS_TYPE (object_class),
-                   GTK_SIGNAL_OFFSET (GtkEditableClass, paste_clipboard),
-                   gtk_marshal_VOID__VOID,
-                   GTK_TYPE_NONE, 0);
-
-  gtk_object_class_add_signals (object_class, editable_signals, LAST_SIGNAL);
-
-  gtk_object_add_arg_type ("GtkEditable::text_position", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_TEXT_POSITION);
-  gtk_object_add_arg_type ("GtkEditable::editable", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_EDITABLE);
-    
-  object_class->set_arg = gtk_editable_set_arg;
-  object_class->get_arg = gtk_editable_get_arg;
-
-  widget_class->selection_clear_event = gtk_editable_selection_clear;
-  widget_class->selection_received = gtk_editable_selection_received;
-  widget_class->selection_get = gtk_editable_selection_get;
-
-  class->insert_text = NULL;
-  class->delete_text = NULL;
-
-  class->activate = NULL;
-  class->set_editable = gtk_editable_real_set_editable;
-
-  class->move_cursor = NULL;
-  class->move_word = NULL;
-  class->move_page = NULL;
-  class->move_to_row = NULL;
-  class->move_to_column = NULL;
-
-  class->kill_char = NULL;
-  class->kill_word = NULL;
-  class->kill_line = NULL;
-
-  class->cut_clipboard = gtk_editable_real_cut_clipboard;
-  class->copy_clipboard = gtk_editable_real_copy_clipboard;
-  class->paste_clipboard = gtk_editable_real_paste_clipboard;
-
-  class->update_text = NULL;
-  class->get_chars = NULL;
-  class->set_selection = NULL;
-  class->set_position = NULL;
-}
-
-static void
-gtk_editable_set_arg (GtkObject      *object,
-                     GtkArg         *arg,
-                     guint           arg_id)
-{
-  GtkEditable *editable;
-
-  editable = GTK_EDITABLE (object);
-
-  switch (arg_id)
-    {
-    case ARG_TEXT_POSITION:
-      gtk_editable_set_position (editable, GTK_VALUE_INT (*arg));
-      break;
-    case ARG_EDITABLE:
-      gtk_editable_set_editable (editable, GTK_VALUE_BOOL (*arg));
-      break;
-    default:
-      break;
-    }
-}
-
-static void
-gtk_editable_get_arg (GtkObject      *object,
-                     GtkArg         *arg,
-                     guint           arg_id)
-{
-  GtkEditable *editable;
-
-  editable = GTK_EDITABLE (object);
-
-  switch (arg_id)
-    {
-    case ARG_TEXT_POSITION:
-      GTK_VALUE_INT (*arg) = editable->current_pos;
-      break;
-    case ARG_EDITABLE:
-      GTK_VALUE_BOOL (*arg) = editable->editable;
-      break;
-    default:
-      arg->type = GTK_TYPE_INVALID;
-      break;
-    }
-}
-
-static void
-gtk_editable_init (GtkEditable *editable)
-{
-  static const GtkTargetEntry targets[] = {
-    { "STRING", 0, TARGET_STRING },
-    { "TEXT",   0, TARGET_TEXT }, 
-    { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT }
-  };
-  static const gint n_targets = sizeof(targets) / sizeof(targets[0]);
-  
-  GTK_WIDGET_SET_FLAGS (editable, GTK_CAN_FOCUS);
-
-  editable->selection_start_pos = 0;
-  editable->selection_end_pos = 0;
-  editable->has_selection = FALSE;
-  editable->editable = 1;
-  editable->visible = 1;
-  editable->clipboard_text = NULL;
-
-#ifdef USE_XIM
-  editable->ic = NULL;
-#endif
-
-  if (!clipboard_atom)
-    clipboard_atom = gdk_atom_intern ("CLIPBOARD", FALSE);
-
-  gtk_selection_add_targets (GTK_WIDGET (editable), GDK_SELECTION_PRIMARY,
-                            targets, n_targets);
-  gtk_selection_add_targets (GTK_WIDGET (editable), clipboard_atom,
-                            targets, n_targets);
-}
-
 void
 gtk_editable_insert_text (GtkEditable *editable,
                          const gchar *new_text,
                          gint         new_text_length,
                          gint        *position)
 {
-  GtkEditableClass *klass;
-  gchar buf[64];
-  gchar *text;
-
-  g_return_if_fail (editable != NULL);
   g_return_if_fail (GTK_IS_EDITABLE (editable));
-
-  gtk_widget_ref (GTK_WIDGET (editable));
-
-  klass = GTK_EDITABLE_GET_CLASS (editable);
+  g_return_if_fail (position != NULL);
 
   if (new_text_length < 0)
     new_text_length = strlen (new_text);
   
-  if (new_text_length <= 64)
-    text = buf;
-  else
-    text = g_new (gchar, new_text_length);
-
-  strncpy (text, new_text, new_text_length);
-
-  gtk_signal_emit (GTK_OBJECT (editable), editable_signals[INSERT_TEXT], text, new_text_length, position);
-  gtk_signal_emit (GTK_OBJECT (editable), editable_signals[CHANGED]);
-
-  if (new_text_length > 64)
-    g_free (text);
-
-  gtk_widget_unref (GTK_WIDGET (editable));
+  GTK_EDITABLE_GET_CLASS (editable)->insert_text (editable, new_text, new_text_length, position);
 }
 
 void
@@ -448,360 +69,67 @@ gtk_editable_delete_text (GtkEditable *editable,
                          gint         start_pos,
                          gint         end_pos)
 {
-  GtkEditableClass *klass;
-
-  g_return_if_fail (editable != NULL);
   g_return_if_fail (GTK_IS_EDITABLE (editable));
 
-  gtk_widget_ref (GTK_WIDGET (editable));
-
-  klass = GTK_EDITABLE_GET_CLASS (editable);
-
-  gtk_signal_emit (GTK_OBJECT (editable), editable_signals[DELETE_TEXT], start_pos, end_pos);
-  gtk_signal_emit (GTK_OBJECT (editable), editable_signals[CHANGED]);
-
-  gtk_widget_unref (GTK_WIDGET (editable));
-}
-
-static void
-gtk_editable_update_text (GtkEditable *editable,
-                      gint      start_pos,
-                      gint      end_pos)
-{
-  GtkEditableClass *klass;
-
-  g_return_if_fail (editable != NULL);
-  g_return_if_fail (GTK_IS_EDITABLE (editable));
-
-  klass = GTK_EDITABLE_GET_CLASS (editable);
-
-  klass->update_text (editable, start_pos, end_pos);
+  GTK_EDITABLE_GET_CLASS (editable)->delete_text (editable, start_pos, end_pos);
 }
 
 gchar *    
-gtk_editable_get_chars      (GtkEditable      *editable,
-                            gint              start,
-                            gint              end)
-{
-  GtkEditableClass *klass;
-
-  g_return_val_if_fail (editable != NULL, NULL);
-  g_return_val_if_fail (GTK_IS_EDITABLE (editable), NULL);
-
-  klass = GTK_EDITABLE_GET_CLASS (editable);
-
-  return klass->get_chars (editable, start, end);
-}
-
-/*
- * Like gtk_editable_get_chars, but if the editable is not
- * visible, return asterisks
- */
-static void *    
-gtk_editable_get_public_chars (GtkEditable      *editable,
-                              gint              start,
-                              gint              end)
-{
-  if (editable->visible)
-    return gtk_editable_get_chars (editable, start, end);
-  else
-    {
-      gint i;
-      gint nchars = end - start;
-      gchar *str;
-       
-      if (nchars < 0)
-       nchars = -nchars;
-
-      str = g_new (gchar, nchars + 1);
-      for (i = 0; i<nchars; i++)
-       str[i] = '*';
-      str[i] = '\0';
-
-      return str;
-    }
-}
-
-static void
-gtk_editable_set_selection (GtkEditable *editable,
-                           gint      start_pos,
-                           gint      end_pos)
+gtk_editable_get_chars (GtkEditable *editable,
+                       gint         start,
+                       gint         end)
 {
-  GtkEditableClass *klass;
-
-  g_return_if_fail (editable != NULL);
-  g_return_if_fail (GTK_IS_EDITABLE (editable));
+  g_return_val_if_fail (GTK_IS_EDITABLE (editable), FALSE);
 
-  klass = GTK_EDITABLE_GET_CLASS (editable);
-
-  klass->set_selection (editable, start_pos, end_pos);
+  return GTK_EDITABLE_GET_CLASS (editable)->get_chars (editable, start, end);
 }
 
 void
 gtk_editable_set_position (GtkEditable      *editable,
                           gint              position)
 {
-  GtkEditableClass *klass;
-
-  g_return_if_fail (editable != NULL);
   g_return_if_fail (GTK_IS_EDITABLE (editable));
 
-  klass = GTK_EDITABLE_GET_CLASS (editable);
-
-  klass->set_position (editable, position);
+  GTK_EDITABLE_GET_CLASS (editable)->set_position (editable, position);
 }
 
 gint
 gtk_editable_get_position (GtkEditable      *editable)
 {
-  g_return_val_if_fail (editable != NULL, -1);
-  g_return_val_if_fail (GTK_IS_EDITABLE (editable), -1);
-
-  return editable->current_pos;
-}
+  g_return_val_if_fail (GTK_IS_EDITABLE (editable), 0);
 
-static gint
-gtk_editable_selection_clear (GtkWidget         *widget,
-                             GdkEventSelection *event)
-{
-  GtkEditable *editable;
-  
-  g_return_val_if_fail (widget != NULL, FALSE);
-  g_return_val_if_fail (GTK_IS_EDITABLE (widget), FALSE);
-  g_return_val_if_fail (event != NULL, FALSE);
-  
-  /* Let the selection handling code know that the selection
-   * has been changed, since we've overriden the default handler */
-  if (!gtk_selection_clear (widget, event))
-    return FALSE;
-  
-  editable = GTK_EDITABLE (widget);
-  
-  if (event->selection == GDK_SELECTION_PRIMARY)
-    {
-      if (editable->has_selection)
-       {
-         editable->has_selection = FALSE;
-         gtk_editable_update_text (editable, editable->selection_start_pos,
-                                   editable->selection_end_pos);
-       }
-    }
-  else if (event->selection == clipboard_atom)
-    {
-      g_free (editable->clipboard_text);
-      editable->clipboard_text = NULL;
-    }
-  
-  return TRUE;
+  return GTK_EDITABLE_GET_CLASS (editable)->get_position (editable);
 }
 
-static void
-gtk_editable_selection_get (GtkWidget        *widget,
-                           GtkSelectionData *selection_data,
-                           guint             info,
-                           guint             time)
+gboolean
+gtk_editable_get_selection_bounds (GtkEditable *editable,
+                                  gint        *start_pos,
+                                  gint        *end_pos)
 {
-  GtkEditable *editable;
-  gint selection_start_pos;
-  gint selection_end_pos;
-
-  gchar *str;
-  gint length;
-
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (GTK_IS_EDITABLE (widget));
-
-  editable = GTK_EDITABLE (widget);
-
-  if (selection_data->selection == GDK_SELECTION_PRIMARY)
-    {
-      selection_start_pos = MIN (editable->selection_start_pos, editable->selection_end_pos);
-      selection_end_pos = MAX (editable->selection_start_pos, editable->selection_end_pos);
-      str = gtk_editable_get_public_chars(editable, 
-                                         selection_start_pos, 
-                                         selection_end_pos);
-      if (!str)
-        return;                /* Refuse */
-      length = strlen (str);
-    }
-  else                         /* CLIPBOARD */
-    {
-      if (!editable->clipboard_text)
-       return;                 /* Refuse */
-
-      str = editable->clipboard_text;
-      length = strlen (editable->clipboard_text);
-    }
+  gint tmp_start, tmp_end;
+  gboolean result;
   
-  if (info == TARGET_STRING)
-    {
-      gtk_selection_data_set (selection_data,
-                              GDK_SELECTION_TYPE_STRING,
-                              8*sizeof(gchar), (guchar *)str, length);
-    }
-  else if ((info == TARGET_TEXT) || (info == TARGET_COMPOUND_TEXT))
-    {
-      guchar *text;
-      gchar c;
-      GdkAtom encoding;
-      gint format;
-      gint new_length;
-
-      c = str[length];
-      str[length] = '\0';
-      gdk_string_to_compound_text (str, &encoding, &format, &text, &new_length);
-      gtk_selection_data_set (selection_data, encoding, format, text, new_length);
-      gdk_free_compound_text (text);
-      str[length] = c;
-    }
-
-  if (str != editable->clipboard_text)
-    g_free (str);
-}
-
-static void
-gtk_editable_selection_received  (GtkWidget         *widget,
-                                 GtkSelectionData  *selection_data,
-                                 guint              time)
-{
-  GtkEditable *editable;
-  gint reselect;
-  gint old_pos;
-  gint tmp_pos;
-  enum {INVALID, STRING, CTEXT} type;
-
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (GTK_IS_EDITABLE (widget));
-
-  editable = GTK_EDITABLE (widget);
-
-  if (selection_data->type == GDK_TARGET_STRING)
-    type = STRING;
-  else if ((selection_data->type == gdk_atom_intern ("COMPOUND_TEXT", FALSE)) ||
-          (selection_data->type == gdk_atom_intern ("TEXT", FALSE)))
-    type = CTEXT;
-  else
-    type = INVALID;
-
-  if (type == INVALID || selection_data->length < 0)
-    {
-    /* avoid infinite loop */
-    if (selection_data->target != GDK_TARGET_STRING)
-      gtk_selection_convert (widget, selection_data->selection,
-                            GDK_TARGET_STRING, time);
-    return;
-  }
-
-  reselect = FALSE;
+  g_return_val_if_fail (GTK_IS_EDITABLE (editable), FALSE);
 
-  if ((editable->selection_start_pos != editable->selection_end_pos) && 
-      (!editable->has_selection || 
-       (selection_data->selection == clipboard_atom)))
-    {
-      reselect = TRUE;
-
-      /* Don't want to call gtk_editable_delete_selection here if we are going
-       * to reclaim the selection to avoid extra server traffic */
-      if (editable->has_selection)
-       {
-         gtk_editable_delete_text (editable,
-                                MIN (editable->selection_start_pos, editable->selection_end_pos),
-                                MAX (editable->selection_start_pos, editable->selection_end_pos));
-       }
-      else
-       gtk_editable_delete_selection (editable);
-    }
+  result = GTK_EDITABLE_GET_CLASS (editable)->get_selection_bounds (editable, &tmp_start, &tmp_end);
 
-  tmp_pos = old_pos = editable->current_pos;
+  if (start_pos)
+    *start_pos = MIN (tmp_start, tmp_end);
+  if (end_pos)
+    *end_pos = MAX (tmp_start, tmp_end);
 
-  switch (type)
-    {
-    case STRING:
-      selection_data->data[selection_data->length] = 0;
-      gtk_editable_insert_text (editable, (gchar *)selection_data->data,
-                               strlen ((gchar *)selection_data->data), 
-                               &tmp_pos);
-      editable->current_pos = tmp_pos;
-      break;
-    case CTEXT:
-      {
-       gchar **list;
-       gint count;
-       gint i;
-
-       count = gdk_text_property_to_text_list (selection_data->type,
-                                               selection_data->format, 
-                                               selection_data->data,
-                                               selection_data->length,
-                                               &list);
-       for (i=0; i<count; i++) 
-         {
-           gtk_editable_insert_text (editable, list[i], strlen (list[i]), &tmp_pos);
-           editable->current_pos = tmp_pos;
-         }
-       if (count > 0)
-         gdk_free_text_list (list);
-      }
-      break;
-    case INVALID:              /* quiet compiler */
-      break;
-    }
-
-  if (reselect)
-    gtk_editable_set_selection (editable, old_pos, editable->current_pos);
+  return result;
 }
 
 void
 gtk_editable_delete_selection (GtkEditable *editable)
 {
-  guint start;
-  guint end;
+  gint start, end;
 
-  g_return_if_fail (editable != NULL);
   g_return_if_fail (GTK_IS_EDITABLE (editable));
 
-  if (!editable->editable)
-    return;
-
-  start = editable->selection_start_pos;
-  end = editable->selection_end_pos;
-
-  editable->selection_start_pos = 0;
-  editable->selection_end_pos = 0;
-
-  if (start != end)
-    gtk_editable_delete_text (editable, MIN (start, end), MAX (start,end));
-
-  if (editable->has_selection)
-    {
-      editable->has_selection = FALSE;
-      if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == GTK_WIDGET (editable)->window)
-       gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME);
-    }
-}
-
-void
-gtk_editable_claim_selection (GtkEditable *editable, 
-                             gboolean  claim, 
-                             guint32   time)
-{
-  g_return_if_fail (editable != NULL);
-  g_return_if_fail (GTK_IS_EDITABLE (editable));
-  g_return_if_fail (GTK_WIDGET_REALIZED (editable));
-
-  editable->has_selection = FALSE;
-  
-  if (claim)
-    {
-      if (gtk_selection_owner_set (GTK_WIDGET(editable), GDK_SELECTION_PRIMARY, time))
-       editable->has_selection = TRUE;
-    }
-  else
-    {
-      if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == 
-         GTK_WIDGET(editable)->window)
-       gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, time);
-    }
+  if (gtk_editable_get_selection_bounds (editable, &start, &end))
+    gtk_editable_delete_text (editable, start, end);
 }
 
 void
@@ -809,57 +137,9 @@ gtk_editable_select_region (GtkEditable *editable,
                            gint         start,
                            gint         end)
 {
-  g_return_if_fail (editable != NULL);
   g_return_if_fail (GTK_IS_EDITABLE (editable));
   
-  if (GTK_WIDGET_REALIZED (editable))
-    gtk_editable_claim_selection (editable, start != end, GDK_CURRENT_TIME);
-  
-  gtk_editable_set_selection (editable, start, end);
-}
-
-/* Get the timestamp of the current event. Actually, the only thing
- * we really care about below is the key event
- */
-static guint32
-gtk_editable_get_event_time (GtkEditable *editable)
-{
-  GdkEvent *event;
-  guint32 tm = GDK_CURRENT_TIME;
-  
-  event = gtk_get_current_event();
-  
-  if (event)
-    switch (event->type)
-      {
-      case GDK_MOTION_NOTIFY:
-       tm = event->motion.time; break;
-      case GDK_BUTTON_PRESS:
-      case GDK_2BUTTON_PRESS:
-      case GDK_3BUTTON_PRESS:
-      case GDK_BUTTON_RELEASE:
-       tm = event->button.time; break;
-      case GDK_KEY_PRESS:
-      case GDK_KEY_RELEASE:
-       tm = event->key.time; break;
-      case GDK_ENTER_NOTIFY:
-      case GDK_LEAVE_NOTIFY:
-       tm = event->crossing.time; break;
-      case GDK_PROPERTY_NOTIFY:
-       tm = event->property.time; break;
-      case GDK_SELECTION_CLEAR:
-      case GDK_SELECTION_REQUEST:
-      case GDK_SELECTION_NOTIFY:
-       tm = event->selection.time; break;
-      case GDK_PROXIMITY_IN:
-      case GDK_PROXIMITY_OUT:
-       tm = event->proximity.time; break;
-      default:                 /* use current time */
-       break;
-      }
-  gdk_event_free(event);
-  
-  return tm;
+  GTK_EDITABLE_GET_CLASS (editable)->set_selection_bounds (editable,  start, end);
 }
 
 void
@@ -868,7 +148,7 @@ gtk_editable_cut_clipboard (GtkEditable *editable)
   g_return_if_fail (editable != NULL);
   g_return_if_fail (GTK_IS_EDITABLE (editable));
   
-  gtk_signal_emit (GTK_OBJECT (editable), editable_signals[CUT_CLIPBOARD]);
+  gtk_signal_emit_by_name (GTK_OBJECT (editable), "cut_clipboard");
 }
 
 void
@@ -877,7 +157,7 @@ gtk_editable_copy_clipboard (GtkEditable *editable)
   g_return_if_fail (editable != NULL);
   g_return_if_fail (GTK_IS_EDITABLE (editable));
   
-  gtk_signal_emit (GTK_OBJECT (editable), editable_signals[COPY_CLIPBOARD]);
+  gtk_signal_emit_by_name (GTK_OBJECT (editable), "copy_clipboard");
 }
 
 void
@@ -886,85 +166,16 @@ gtk_editable_paste_clipboard (GtkEditable *editable)
   g_return_if_fail (editable != NULL);
   g_return_if_fail (GTK_IS_EDITABLE (editable));
   
-  gtk_signal_emit (GTK_OBJECT (editable), editable_signals[PASTE_CLIPBOARD]);
+  gtk_signal_emit_by_name (GTK_OBJECT (editable), "paste_clipboard");
 }
 
 void
 gtk_editable_set_editable (GtkEditable    *editable,
                           gboolean        is_editable)
 {
-  g_return_if_fail (editable != NULL);
   g_return_if_fail (GTK_IS_EDITABLE (editable));
-  
-  gtk_signal_emit (GTK_OBJECT (editable), editable_signals[SET_EDITABLE], is_editable != FALSE);
-}
 
-static void
-gtk_editable_real_set_editable (GtkEditable    *editable,
-                               gboolean        is_editable)
-{
-  g_return_if_fail (editable != NULL);
-  g_return_if_fail (GTK_IS_EDITABLE (editable));
-
-  editable->editable = is_editable != FALSE;
-  gtk_widget_queue_draw (GTK_WIDGET (editable));
-}
-
-static void
-gtk_editable_real_cut_clipboard (GtkEditable *editable)
-{
-  g_return_if_fail (editable != NULL);
-  g_return_if_fail (GTK_IS_EDITABLE (editable));
-  
-  gtk_editable_real_copy_clipboard (editable);
-  gtk_editable_delete_selection (editable);
-}
-
-static void
-gtk_editable_real_copy_clipboard (GtkEditable *editable)
-{
-  guint32 time;
-  gint selection_start_pos; 
-  gint selection_end_pos;
-
-  g_return_if_fail (editable != NULL);
-  g_return_if_fail (GTK_IS_EDITABLE (editable));
-  
-  time = gtk_editable_get_event_time (editable);
-  selection_start_pos = MIN (editable->selection_start_pos, editable->selection_end_pos);
-  selection_end_pos = MAX (editable->selection_start_pos, editable->selection_end_pos);
-  if (selection_start_pos != selection_end_pos)
-    {
-      if (gtk_selection_owner_set (GTK_WIDGET (editable),
-                                  clipboard_atom,
-                                  time))
-       editable->clipboard_text = gtk_editable_get_public_chars (editable,
-                                                                 selection_start_pos,
-                                                                 selection_end_pos);
-    }
-}
-
-static void
-gtk_editable_real_paste_clipboard (GtkEditable *editable)
-{
-  guint32 time;
-
-  g_return_if_fail (editable != NULL);
-  g_return_if_fail (GTK_IS_EDITABLE (editable));
-  
-  time = gtk_editable_get_event_time (editable);
-  if (editable->editable)
-    gtk_selection_convert (GTK_WIDGET(editable), 
-                          clipboard_atom, 
-                          gdk_atom_intern ("COMPOUND_TEXT", FALSE), time);
-}
-
-void
-gtk_editable_changed (GtkEditable *editable)
-{
-  g_return_if_fail (editable != NULL);
-  g_return_if_fail (GTK_IS_EDITABLE (editable));
-  
-  gtk_signal_emit (GTK_OBJECT (editable), editable_signals[CHANGED]);
+  gtk_object_set (GTK_OBJECT (editable),
+                 "editable", is_editable != FALSE,
+                 NULL);
 }
index 55c1c22e9ec6275c06fddb158e7bdc6e6eab4e55..9fb5ba06adaadbc3af05e93507245e6e401e7161 100644 (file)
 #include <gdk/gdk.h>
 #include <gtk/gtkwidget.h>
 
-
 #ifdef __cplusplus
 extern "C" {
 #endif /* __cplusplus */
 
 
-#define GTK_TYPE_EDITABLE            (gtk_editable_get_type ())
-#define GTK_EDITABLE(obj)            (GTK_CHECK_CAST ((obj), GTK_TYPE_EDITABLE, GtkEditable))
-#define GTK_EDITABLE_CLASS(klass)    (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_EDITABLE, GtkEditableClass))
-#define GTK_IS_EDITABLE(obj)         (GTK_CHECK_TYPE ((obj), GTK_TYPE_EDITABLE))
-#define GTK_IS_EDITABLE_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_EDITABLE))
-#define GTK_EDITABLE_GET_CLASS(obj)  (GTK_CHECK_GET_CLASS ((obj), GTK_TYPE_EDITABLE, GtkEditableClass))
-
+#define GTK_TYPE_EDITABLE             (gtk_editable_get_type ())
+#define GTK_EDITABLE(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_EDITABLE, GtkEditable))
+#define GTK_EDITABLE_CLASS(vtable)    (G_TYPE_CHECK_CLASS_CAST ((vtable), GTK_TYPE_EDITABLE, GtkEditableClass))
+#define GTK_IS_EDITABLE(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_EDITABLE))
+#define GTK_IS_EDITABLE_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), GTK_TYPE_EDITABLE))
+#define GTK_EDITABLE_GET_CLASS(inst)  (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GTK_TYPE_EDITABLE, GtkEditableClass))
 
-typedef struct _GtkEditable       GtkEditable;
+typedef struct _GtkEditable       GtkEditable;         /* Dummy typedef */
 typedef struct _GtkEditableClass  GtkEditableClass;
 
-typedef void (*GtkTextFunction) (GtkEditable  *editable, guint32 time);
-
-struct _GtkEditable
-{
-  GtkWidget widget;
-
-  /*< public >*/
-  guint      current_pos;
-
-  guint      selection_start_pos;
-  guint      selection_end_pos;
-  guint      has_selection : 1;
-
-  /*< private >*/
-  guint      editable : 1;
-  guint      visible : 1;
-  GdkIC     *ic;
-  GdkICAttr *ic_attr;
-  
-  gchar *clipboard_text;
-};
-
 struct _GtkEditableClass
 {
-  GtkWidgetClass parent_class;
+  GTypeInterface                  base_iface;
   
   /* Signals for notification/filtering of changes */
-  void (* changed)      (GtkEditable    *editable);
-  void (* insert_text)  (GtkEditable    *editable,
-                        const gchar    *text,
-                        gint            length,
-                        gint           *position);
-  void (* delete_text)  (GtkEditable    *editable,
-                        gint            start_pos,
-                        gint            end_pos);
-
-  /* Bindings actions */
-  void (* activate)        (GtkEditable *editable);
-  void (* set_editable)    (GtkEditable *editable,
-                           gboolean     is_editable);
-  void (* move_cursor)     (GtkEditable *editable,
-                           gint         x,
-                           gint         y);
-  void (* move_word)       (GtkEditable *editable,
-                           gint         n);
-  void (* move_page)       (GtkEditable *editable,
-                           gint         x,
-                           gint         y);
-  void (* move_to_row)     (GtkEditable *editable,
-                           gint         row);
-  void (* move_to_column)  (GtkEditable *editable,
-                           gint         row);
-  void (* kill_char)       (GtkEditable *editable,
-                           gint         direction);
-  void (* kill_word)       (GtkEditable *editable,
-                           gint         direction);
-  void (* kill_line)       (GtkEditable *editable,
-                           gint         direction);
-  void (* cut_clipboard)   (GtkEditable *editable);
-  void (* copy_clipboard)  (GtkEditable *editable);
-  void (* paste_clipboard) (GtkEditable *editable);
-
-  /* Virtual functions. get_chars is in paricular not a signal because
-   * it returns malloced memory. The others are not signals because
-   * they would not be particularly useful as such. (All changes to
-   * selection and position do not go through these functions)
-   */
-  void (* update_text)  (GtkEditable    *editable,
-                        gint            start_pos,
-                        gint            end_pos);
-  gchar* (* get_chars)  (GtkEditable    *editable,
-                        gint            start_pos,
-                        gint            end_pos);
-  void (* set_selection)(GtkEditable    *editable,
-                        gint            start_pos,
-                        gint            end_pos);
-  void (* set_position) (GtkEditable    *editable,
-                        gint            position);
+  void (* insert_text)              (GtkEditable    *editable,
+                                    const gchar    *text,
+                                    gint            length,
+                                    gint           *position);
+  void (* delete_text)              (GtkEditable    *editable,
+                                    gint            start_pos,
+                                    gint            end_pos);
+  gchar* (* get_chars)              (GtkEditable    *editable,
+                                    gint            start_pos,
+                                    gint            end_pos);
+  void (* set_selection_bounds)     (GtkEditable    *editable,
+                                    gint            start_pos,
+                                    gint            end_pos);
+  gboolean (* get_selection_bounds) (GtkEditable    *editable,
+                                    gint           *start_pos,
+                                    gint           *end_pos);
+  void (* set_position)             (GtkEditable    *editable,
+                                    gint            position);
+  gint (* get_position)             (GtkEditable    *editable);
 };
 
-GtkType    gtk_editable_get_type       (void) G_GNUC_CONST;
-void       gtk_editable_select_region  (GtkEditable      *editable,
-                                       gint              start,
-                                       gint              end);
-void       gtk_editable_insert_text   (GtkEditable       *editable,
-                                       const gchar      *new_text,
-                                       gint              new_text_length,
-                                       gint             *position);
-void       gtk_editable_delete_text    (GtkEditable      *editable,
-                                       gint              start_pos,
-                                       gint              end_pos);
-gchar*     gtk_editable_get_chars      (GtkEditable      *editable,
-                                       gint              start_pos,
-                                       gint              end_pos);
-void       gtk_editable_cut_clipboard  (GtkEditable      *editable);
-void       gtk_editable_copy_clipboard (GtkEditable      *editable);
-void       gtk_editable_paste_clipboard (GtkEditable     *editable);
-void       gtk_editable_claim_selection (GtkEditable     *editable, 
-                                        gboolean         claim, 
-                                        guint32          time);
-void       gtk_editable_delete_selection (GtkEditable    *editable);
-
-void       gtk_editable_changed         (GtkEditable    *editable);
-void       gtk_editable_set_position    (GtkEditable    *editable,
-                                        gint            position);
-gint       gtk_editable_get_position    (GtkEditable    *editable);
-void       gtk_editable_set_editable    (GtkEditable    *editable,
-                                        gboolean        is_editable);
-
+GtkType  gtk_editable_get_type             (void) G_GNUC_CONST;
+void     gtk_editable_select_region        (GtkEditable *editable,
+                                           gint         start,
+                                           gint         end);
+gboolean gtk_editable_get_selection_bounds (GtkEditable *editable,
+                                           gint        *start,
+                                           gint        *end);
+void     gtk_editable_insert_text          (GtkEditable *editable,
+                                           const gchar *new_text,
+                                           gint         new_text_length,
+                                           gint        *position);
+void     gtk_editable_delete_text          (GtkEditable *editable,
+                                           gint         start_pos,
+                                           gint         end_pos);
+gchar*   gtk_editable_get_chars            (GtkEditable *editable,
+                                           gint         start_pos,
+                                           gint         end_pos);
+void     gtk_editable_cut_clipboard        (GtkEditable *editable);
+void     gtk_editable_copy_clipboard       (GtkEditable *editable);
+void     gtk_editable_paste_clipboard      (GtkEditable *editable);
+void     gtk_editable_delete_selection     (GtkEditable *editable);
+void     gtk_editable_set_position         (GtkEditable *editable,
+                                           gint         position);
+gint     gtk_editable_get_position         (GtkEditable *editable);
+void     gtk_editable_set_editable         (GtkEditable *editable,
+                                           gboolean     is_editable);
 
 #ifdef __cplusplus
 }
index 050709181a3e05756cb53a18dadf30fe62b426fb..fcffeedf4b1c09e924bd88cf2c7432ebce7ec529 100644 (file)
  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
  */
 
-#include <ctype.h>
 #include <string.h>
+
+#include <pango/pango.h>
+
 #include "gdk/gdkkeysyms.h"
-#include "gdk/gdki18n.h"
+#include "gtkbindings.h"
+#include "gtkclipboard.h"
 #include "gtkentry.h"
 #include "gtkimmulticontext.h"
+#include "gtkintl.h"
 #include "gtkmain.h"
+#include "gtkmenu.h"
+#include "gtkmenuitem.h"
 #include "gtkselection.h"
 #include "gtksignal.h"
-#include "gtkstyle.h"
-
-#include <pango/pango.h>
-#include <glib-object.h>
 
 #define MIN_ENTRY_WIDTH  150
 #define DRAW_TIMEOUT     20
 /* Maximum size of text buffer, in bytes */
 #define MAX_SIZE G_MAXUSHORT
 
+enum {
+  INSERT_TEXT,
+  DELETE_TEXT,
+  CHANGED,
+  ACTIVATE,
+  MOVE_CURSOR,
+  INSERT_AT_CURSOR,
+  DELETE_FROM_CURSOR,
+  CUT_CLIPBOARD,
+  COPY_CLIPBOARD,
+  PASTE_CLIPBOARD,
+  TOGGLE_OVERWRITE,
+  LAST_SIGNAL
+};
+
 enum {
   ARG_0,
+  ARG_TEXT_POSITION,
+  ARG_EDITABLE,
   ARG_MAX_LENGTH,
   ARG_VISIBILITY
 };
 
+static guint signals[LAST_SIGNAL] = { 0 };
 
+/* GObject, GtkObject methods
+ */
 static void   gtk_entry_class_init           (GtkEntryClass    *klass);
+static void   gtk_entry_editable_init        (GtkEditableClass *iface);
 static void   gtk_entry_init                 (GtkEntry         *entry);
 static void   gtk_entry_set_arg              (GtkObject        *object,
                                              GtkArg           *arg,
@@ -64,15 +87,18 @@ static void   gtk_entry_get_arg              (GtkObject        *object,
                                              GtkArg           *arg,
                                              guint             arg_id);
 static void   gtk_entry_finalize             (GObject          *object);
+
+/* GtkWidget methods
+ */
 static void   gtk_entry_realize              (GtkWidget        *widget);
 static void   gtk_entry_unrealize            (GtkWidget        *widget);
-static void   gtk_entry_draw_focus           (GtkWidget        *widget);
 static void   gtk_entry_size_request         (GtkWidget        *widget,
                                              GtkRequisition   *requisition);
 static void   gtk_entry_size_allocate        (GtkWidget        *widget,
                                              GtkAllocation    *allocation);
 static void   gtk_entry_draw                 (GtkWidget        *widget,
                                              GdkRectangle     *area);
+static void   gtk_entry_draw_focus           (GtkWidget        *widget);
 static gint   gtk_entry_expose               (GtkWidget        *widget,
                                              GdkEventExpose   *event);
 static gint   gtk_entry_button_press         (GtkWidget        *widget,
@@ -87,145 +113,100 @@ static gint   gtk_entry_focus_in             (GtkWidget        *widget,
                                              GdkEventFocus    *event);
 static gint   gtk_entry_focus_out            (GtkWidget        *widget,
                                              GdkEventFocus    *event);
-static void   gtk_entry_draw_text            (GtkEntry         *entry);
-static void   gtk_entry_ensure_layout        (GtkEntry         *entry);
-static void   gtk_entry_draw_cursor          (GtkEntry         *entry);
 static void   gtk_entry_style_set            (GtkWidget        *widget,
                                              GtkStyle         *previous_style);
 static void   gtk_entry_direction_changed    (GtkWidget        *widget,
                                              GtkTextDirection  previous_dir);
 static void   gtk_entry_state_changed        (GtkWidget        *widget,
                                              GtkStateType      previous_state);
-static void   gtk_entry_queue_draw           (GtkEntry         *entry);
-static gint   gtk_entry_find_position        (GtkEntry         *entry,
-                                             gint              x);
-static void   gtk_entry_get_cursor_locations (GtkEntry         *entry,
-                                             gint             *strong_x,
-                                             gint             *weak_x);
-static void   entry_adjust_scroll            (GtkEntry         *entry);
-static void   gtk_entry_insert_text          (GtkEditable      *editable,
-                                             const gchar      *new_text,
-                                             gint              new_text_length,
-                                             gint             *position);
-static void   gtk_entry_delete_text          (GtkEditable      *editable,
-                                             gint              start_pos,
-                                             gint              end_pos);
-static void   gtk_entry_update_text          (GtkEditable      *editable,
-                                             gint              start_pos,
-                                             gint              end_pos);
-static gchar *gtk_entry_get_chars            (GtkEditable      *editable,
-                                             gint              start_pos,
-                                             gint              end_pos);
-
-/* Binding actions */
-static void gtk_entry_move_cursor         (GtkEditable *editable,
-                                          gint         x,
-                                          gint         y);
-static void gtk_entry_move_word           (GtkEditable *editable,
-                                          gint         n);
-static void gtk_entry_move_to_column      (GtkEditable *editable,
-                                          gint         row);
-static void gtk_entry_kill_char           (GtkEditable *editable,
-                                          gint         direction);
-static void gtk_entry_kill_word           (GtkEditable *editable,
-                                          gint         direction);
-static void gtk_entry_kill_line           (GtkEditable *editable,
-                                          gint         direction);
-
-/* To be removed */
-static void gtk_move_forward_character    (GtkEntry          *entry);
-static void gtk_move_backward_character   (GtkEntry          *entry);
-static void gtk_move_forward_word         (GtkEntry          *entry);
-static void gtk_move_backward_word        (GtkEntry          *entry);
-static void gtk_move_beginning_of_line    (GtkEntry          *entry);
-static void gtk_move_end_of_line          (GtkEntry          *entry);
-static void gtk_delete_forward_character  (GtkEntry          *entry);
-static void gtk_delete_backward_character (GtkEntry          *entry);
-static void gtk_delete_forward_word       (GtkEntry          *entry);
-static void gtk_delete_backward_word      (GtkEntry          *entry);
-static void gtk_delete_line               (GtkEntry          *entry);
-static void gtk_delete_to_line_end        (GtkEntry          *entry);
-static void gtk_select_word               (GtkEntry          *entry,
-                                          guint32            time);
-static void gtk_select_line               (GtkEntry          *entry,
-                                          guint32            time);
-
-
-static void gtk_entry_set_selection       (GtkEditable       *editable,
-                                          gint               start,
-                                          gint               end);
-
-static void gtk_entry_set_position_from_editable (GtkEditable *editable,
-                                                 gint         position);
 
+/* GtkEditable method implementations
+ */
+static void     gtk_entry_insert_text          (GtkEditable *editable,
+                                               const gchar *new_text,
+                                               gint         new_text_length,
+                                               gint        *position);
+static void     gtk_entry_delete_text          (GtkEditable *editable,
+                                               gint         start_pos,
+                                               gint         end_pos);
+static gchar *  gtk_entry_get_chars            (GtkEditable *editable,
+                                               gint         start_pos,
+                                               gint         end_pos);
+static void     gtk_entry_real_set_position    (GtkEditable *editable,
+                                               gint         position);
+static gint     gtk_entry_get_position         (GtkEditable *editable);
+static void     gtk_entry_set_selection_bounds (GtkEditable *editable,
+                                               gint         start,
+                                               gint         end);
+static gboolean gtk_entry_get_selection_bounds (GtkEditable *editable,
+                                               gint        *start,
+                                               gint        *end);
+
+/* Default signal handlers
+ */
+static void gtk_entry_real_insert_text (GtkEntry        *entry,
+                                       const gchar     *new_text,
+                                       gint             new_text_length,
+                                       gint            *position);
+static void gtk_entry_real_delete_text (GtkEntry        *entry,
+                                       gint             start_pos,
+                                       gint             end_pos);
+static void gtk_entry_move             (GtkEntry        *entry,
+                                       GtkMovementStep  step,
+                                       gint             count,
+                                       gboolean         extend_selection);
+static void gtk_entry_insert           (GtkEntry        *entry,
+                                       const gchar     *str);
+static void gtk_entry_delete           (GtkEntry        *entry,
+                                       GtkDeleteType    type,
+                                       gint             count);
+static void gtk_entry_cut_clipboard    (GtkEntry        *entry);
+static void gtk_entry_copy_clipboard   (GtkEntry        *entry);
+static void gtk_entry_paste_clipboard  (GtkEntry        *entry);
+static void gtk_entry_toggle_overwrite (GtkEntry        *entry);
+
+/* IM Context Callbacks
+ */
 static void gtk_entry_commit_cb           (GtkIMContext      *context,
                                           const gchar       *str,
                                           GtkEntry          *entry);
-
+static void gtk_entry_preedit_changed_cb  (GtkIMContext      *context,
+                                          GtkEntry          *entry);
+/* Internal routines
+ */
+static void         gtk_entry_draw_text                (GtkEntry       *entry);
+static void         gtk_entry_draw_cursor              (GtkEntry       *entry);
+static PangoLayout *gtk_entry_get_layout               (GtkEntry       *entry,
+                                                       gboolean        include_preedit);
+static void         gtk_entry_queue_draw               (GtkEntry       *entry);
+static void         gtk_entry_reset_im_context         (GtkEntry       *entry);
+static void         gtk_entry_recompute                (GtkEntry       *entry);
+static gint         gtk_entry_find_position            (GtkEntry       *entry,
+                                                       gint            x);
+static void         gtk_entry_get_cursor_locations     (GtkEntry       *entry,
+                                                       gint           *strong_x,
+                                                       gint           *weak_x);
+static void         gtk_entry_adjust_scroll            (GtkEntry       *entry);
+static gint         gtk_entry_move_visually            (GtkEntry       *editable,
+                                                       gint            start,
+                                                       gint            count);
+static gint         gtk_entry_move_forward_word        (GtkEntry       *entry,
+                                                       gint            start);
+static gint         gtk_entry_move_backward_word       (GtkEntry       *entry,
+                                                       gint            start);
+static void         gtk_entry_delete_whitespace        (GtkEntry       *entry);
+static void         gtk_entry_select_word              (GtkEntry       *entry);
+static void         gtk_entry_select_line              (GtkEntry       *entry);
+static char *       gtk_entry_get_public_chars         (GtkEntry       *entry,
+                                                       gint            start,
+                                                       gint            end);
+static void         gtk_entry_paste                    (GtkEntry       *entry,
+                                                       GdkAtom         selection);
+static void         gtk_entry_update_primary_selection (GtkEntry       *entry);
+static void         gtk_entry_popup_menu               (GtkEntry       *entry,
+                                                       GdkEventButton *event);
 
 static GtkWidgetClass *parent_class = NULL;
-static GdkAtom ctext_atom = GDK_NONE;
-
-static const GtkTextFunction control_keys[26] =
-{
-  (GtkTextFunction)gtk_move_beginning_of_line,    /* a */
-  (GtkTextFunction)gtk_move_backward_character,   /* b */
-  (GtkTextFunction)gtk_editable_copy_clipboard,   /* c */
-  (GtkTextFunction)gtk_delete_forward_character,  /* d */
-  (GtkTextFunction)gtk_move_end_of_line,          /* e */
-  (GtkTextFunction)gtk_move_forward_character,    /* f */
-  NULL,                                           /* g */
-  (GtkTextFunction)gtk_delete_backward_character, /* h */
-  NULL,                                           /* i */
-  NULL,                                           /* j */
-  (GtkTextFunction)gtk_delete_to_line_end,        /* k */
-  NULL,                                           /* l */
-  NULL,                                           /* m */
-  NULL,                                           /* n */
-  NULL,                                           /* o */
-  NULL,                                           /* p */
-  NULL,                                           /* q */
-  NULL,                                           /* r */
-  NULL,                                           /* s */
-  NULL,                                           /* t */
-  (GtkTextFunction)gtk_delete_line,               /* u */
-  (GtkTextFunction)gtk_editable_paste_clipboard,  /* v */
-  (GtkTextFunction)gtk_delete_backward_word,      /* w */
-  (GtkTextFunction)gtk_editable_cut_clipboard,    /* x */
-  NULL,                                           /* y */
-  NULL,                                           /* z */
-};
-
-static const GtkTextFunction alt_keys[26] =
-{
-  NULL,                                           /* a */
-  (GtkTextFunction)gtk_move_backward_word,        /* b */
-  NULL,                                           /* c */
-  (GtkTextFunction)gtk_delete_forward_word,       /* d */
-  NULL,                                           /* e */
-  (GtkTextFunction)gtk_move_forward_word,         /* f */
-  NULL,                                           /* g */
-  NULL,                                           /* h */
-  NULL,                                           /* i */
-  NULL,                                           /* j */
-  NULL,                                           /* k */
-  NULL,                                           /* l */
-  NULL,                                           /* m */
-  NULL,                                           /* n */
-  NULL,                                           /* o */
-  NULL,                                           /* p */
-  NULL,                                           /* q */
-  NULL,                                           /* r */
-  NULL,                                           /* s */
-  NULL,                                           /* t */
-  NULL,                                           /* u */
-  NULL,                                           /* v */
-  NULL,                                           /* w */
-  NULL,                                           /* x */
-  NULL,                                           /* y */
-  NULL,                                           /* z */
-};
-
 
 GtkType
 gtk_entry_get_type (void)
@@ -245,31 +226,291 @@ gtk_entry_get_type (void)
        /* reserved_2 */ NULL,
         (GtkClassInitFunc) NULL,
       };
+      
+      static const GInterfaceInfo editable_info =
+      {
+       (GInterfaceInitFunc) gtk_entry_editable_init,    /* interface_init */
+       NULL,                                            /* interface_finalize */
+       NULL                                             /* interface_data */
+      };
 
-      entry_type = gtk_type_unique (GTK_TYPE_EDITABLE, &entry_info);
+      entry_type = gtk_type_unique (GTK_TYPE_WIDGET, &entry_info);
+      g_type_add_interface_static (entry_type,
+                                  GTK_TYPE_EDITABLE,
+                                  &editable_info);
     }
 
   return entry_type;
 }
 
+static void
+add_move_binding (GtkBindingSet  *binding_set,
+                 guint           keyval,
+                 guint           modmask,
+                 GtkMovementStep step,
+                 gint            count)
+{
+  g_return_if_fail ((modmask & GDK_SHIFT_MASK) == 0);
+  
+  gtk_binding_entry_add_signal (binding_set, keyval, modmask,
+                               "move_cursor", 3,
+                               GTK_TYPE_ENUM, step,
+                               G_TYPE_INT, count,
+                                G_TYPE_BOOLEAN, FALSE);
+
+  /* Selection-extending version */
+  gtk_binding_entry_add_signal (binding_set, keyval, modmask | GDK_SHIFT_MASK,
+                               "move_cursor", 3,
+                               GTK_TYPE_ENUM, step,
+                               G_TYPE_INT, count,
+                                G_TYPE_BOOLEAN, TRUE);
+}
+
 static void
 gtk_entry_class_init (GtkEntryClass *class)
 {
   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
   GtkObjectClass *object_class;
   GtkWidgetClass *widget_class;
-  GtkEditableClass *editable_class;
+
+  GtkBindingSet *binding_set;
 
   object_class = (GtkObjectClass*) class;
   widget_class = (GtkWidgetClass*) class;
-  editable_class = (GtkEditableClass*) class;
-  parent_class = gtk_type_class (GTK_TYPE_EDITABLE);
+  parent_class = gtk_type_class (GTK_TYPE_WIDGET);
 
   gobject_class->finalize = gtk_entry_finalize;
 
-  gtk_object_add_arg_type ("GtkEntry::max_length", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_MAX_LENGTH);
-  gtk_object_add_arg_type ("GtkEntry::visibility", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_VISIBILITY);
+  gtk_object_add_arg_type ("GtkEntry::text_position", GTK_TYPE_INT,  GTK_ARG_READWRITE, ARG_TEXT_POSITION);
+  gtk_object_add_arg_type ("GtkEntry::editable",      GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_EDITABLE);
+  gtk_object_add_arg_type ("GtkEntry::max_length",    GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_MAX_LENGTH);
+  gtk_object_add_arg_type ("GtkEntry::visibility",    GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_VISIBILITY);
+
+  signals[INSERT_TEXT] =
+    gtk_signal_new ("insert_text",
+                   GTK_RUN_LAST,
+                   GTK_CLASS_TYPE (object_class),
+                   GTK_SIGNAL_OFFSET (GtkEntryClass, insert_text),
+                   gtk_marshal_VOID__STRING_INT_POINTER,
+                   GTK_TYPE_NONE,
+                   3,
+                   GTK_TYPE_STRING,
+                   GTK_TYPE_INT,
+                   GTK_TYPE_POINTER);
+
+  signals[DELETE_TEXT] =
+    gtk_signal_new ("delete_text",
+                   GTK_RUN_LAST,
+                   GTK_CLASS_TYPE (object_class),
+                   GTK_SIGNAL_OFFSET (GtkEntryClass, delete_text),
+                   gtk_marshal_VOID__INT_INT,
+                   GTK_TYPE_NONE,
+                   2,
+                   GTK_TYPE_INT,
+                   GTK_TYPE_INT);                  
+
+  signals[CHANGED] =
+    gtk_signal_new ("changed",
+                   GTK_RUN_LAST,
+                   GTK_CLASS_TYPE (object_class),
+                   GTK_SIGNAL_OFFSET (GtkEntryClass, changed),
+                   gtk_marshal_VOID__VOID,
+                   GTK_TYPE_NONE, 0);
+
+ /* Action signals */
+  
+  signals[ACTIVATE] =
+    gtk_signal_new ("activate",
+                   GTK_RUN_LAST | GTK_RUN_ACTION,
+                   GTK_CLASS_TYPE (object_class),
+                   GTK_SIGNAL_OFFSET (GtkEntryClass, activate),
+                   gtk_marshal_VOID__VOID,
+                   GTK_TYPE_NONE, 0);
+
+  widget_class->activate_signal = signals[ACTIVATE];
+
+  signals[MOVE_CURSOR] = 
+      gtk_signal_new ("move_cursor",
+                      GTK_RUN_LAST | GTK_RUN_ACTION,
+                      GTK_CLASS_TYPE (object_class),
+                      GTK_SIGNAL_OFFSET (GtkEntryClass, move),
+                      gtk_marshal_VOID__ENUM_INT_BOOLEAN,
+                      GTK_TYPE_NONE, 3, GTK_TYPE_MOVEMENT_STEP, GTK_TYPE_INT, GTK_TYPE_BOOL);
+
+  signals[INSERT_AT_CURSOR] = 
+      gtk_signal_new ("insert_at_cursor",
+                      GTK_RUN_LAST | GTK_RUN_ACTION,
+                      GTK_CLASS_TYPE (object_class),
+                      GTK_SIGNAL_OFFSET (GtkEntryClass, insert),
+                      gtk_marshal_VOID__STRING,
+                      GTK_TYPE_NONE, 1, GTK_TYPE_STRING);
+
+  signals[DELETE_FROM_CURSOR] = 
+      gtk_signal_new ("delete_from_cursor",
+                      GTK_RUN_LAST | GTK_RUN_ACTION,
+                      GTK_CLASS_TYPE (object_class),
+                      GTK_SIGNAL_OFFSET (GtkEntryClass, delete),
+                      gtk_marshal_VOID__ENUM_INT,
+                      GTK_TYPE_NONE, 2, GTK_TYPE_DELETE_TYPE, GTK_TYPE_INT);
+
+  signals[CUT_CLIPBOARD] =
+    gtk_signal_new ("cut_clipboard",
+                    GTK_RUN_LAST | GTK_RUN_ACTION,
+                    GTK_CLASS_TYPE (object_class),
+                    GTK_SIGNAL_OFFSET (GtkEntryClass, cut_clipboard),
+                    gtk_marshal_VOID__VOID,
+                    GTK_TYPE_NONE, 0);
+
+  signals[COPY_CLIPBOARD] =
+    gtk_signal_new ("copy_clipboard",
+                    GTK_RUN_LAST | GTK_RUN_ACTION,
+                    GTK_CLASS_TYPE (object_class),
+                    GTK_SIGNAL_OFFSET (GtkEntryClass, copy_clipboard),
+                    gtk_marshal_VOID__VOID,
+                    GTK_TYPE_NONE, 0);
+
+  signals[PASTE_CLIPBOARD] =
+    gtk_signal_new ("paste_clipboard",
+                    GTK_RUN_LAST | GTK_RUN_ACTION,
+                    GTK_CLASS_TYPE (object_class),
+                    GTK_SIGNAL_OFFSET (GtkEntryClass, paste_clipboard),
+                    gtk_marshal_VOID__VOID,
+                    GTK_TYPE_NONE, 0);
+
+  signals[TOGGLE_OVERWRITE] =
+    gtk_signal_new ("toggle_overwrite",
+                    GTK_RUN_LAST | GTK_RUN_ACTION,
+                    GTK_CLASS_TYPE (object_class),
+                    GTK_SIGNAL_OFFSET (GtkEntryClass, toggle_overwrite),
+                    gtk_marshal_VOID__VOID,
+                    GTK_TYPE_NONE, 0);
+
+  gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL);
+
+  /*
+   * Key bindings
+   */
+
+  binding_set = gtk_binding_set_by_class (class);
+
+  /* Moving the insertion point */
+  add_move_binding (binding_set, GDK_Right, 0,
+                   GTK_MOVEMENT_POSITIONS, 1);
+  
+  add_move_binding (binding_set, GDK_Left, 0,
+                   GTK_MOVEMENT_POSITIONS, -1);
+
+  add_move_binding (binding_set, GDK_f, GDK_CONTROL_MASK,
+                   GTK_MOVEMENT_CHARS, 1);
+  
+  add_move_binding (binding_set, GDK_b, GDK_CONTROL_MASK,
+                   GTK_MOVEMENT_CHARS, -1);
+  
+  add_move_binding (binding_set, GDK_Right, GDK_CONTROL_MASK,
+                   GTK_MOVEMENT_WORDS, 1);
+
+  add_move_binding (binding_set, GDK_Left, GDK_CONTROL_MASK,
+                   GTK_MOVEMENT_WORDS, -1);
+  
+  add_move_binding (binding_set, GDK_a, GDK_CONTROL_MASK,
+                   GTK_MOVEMENT_PARAGRAPH_ENDS, -1);
+
+  add_move_binding (binding_set, GDK_e, GDK_CONTROL_MASK,
+                   GTK_MOVEMENT_PARAGRAPH_ENDS, 1);
+
+  add_move_binding (binding_set, GDK_f, GDK_MOD1_MASK,
+                   GTK_MOVEMENT_WORDS, 1);
+
+  add_move_binding (binding_set, GDK_b, GDK_MOD1_MASK,
+                   GTK_MOVEMENT_WORDS, -1);
+
+  add_move_binding (binding_set, GDK_Home, 0,
+                   GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
+
+  add_move_binding (binding_set, GDK_End, 0,
+                   GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
+  
+  add_move_binding (binding_set, GDK_Home, GDK_CONTROL_MASK,
+                   GTK_MOVEMENT_BUFFER_ENDS, -1);
+
+  add_move_binding (binding_set, GDK_End, GDK_CONTROL_MASK,
+                   GTK_MOVEMENT_BUFFER_ENDS, 1);
+
+  /* Deleting text */
+  gtk_binding_entry_add_signal (binding_set, GDK_Delete, 0,
+                               "delete_from_cursor", 2,
+                               GTK_TYPE_ENUM, GTK_DELETE_CHARS,
+                               GTK_TYPE_INT, 1);
+
+  gtk_binding_entry_add_signal (binding_set, GDK_d, GDK_CONTROL_MASK,
+                               "delete_from_cursor", 2,
+                               GTK_TYPE_ENUM, GTK_DELETE_CHARS,
+                               GTK_TYPE_INT, 1);
+
+  gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0,
+                               "delete_from_cursor", 2,
+                               GTK_TYPE_ENUM, GTK_DELETE_CHARS,
+                               GTK_TYPE_INT, -1);
+
+  gtk_binding_entry_add_signal (binding_set, GDK_Delete, GDK_CONTROL_MASK,
+                               "delete_from_cursor", 2,
+                               GTK_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
+                               GTK_TYPE_INT, 1);
+
+  gtk_binding_entry_add_signal (binding_set, GDK_d, GDK_MOD1_MASK,
+                               "delete_from_cursor", 2,
+                               GTK_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
+                               GTK_TYPE_INT, 1);
+
+  gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, GDK_CONTROL_MASK,
+                               "delete_from_cursor", 2,
+                               GTK_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
+                               GTK_TYPE_INT, -1);
+
+  gtk_binding_entry_add_signal (binding_set, GDK_k, GDK_CONTROL_MASK,
+                               "delete_from_cursor", 2,
+                               GTK_TYPE_ENUM, GTK_DELETE_PARAGRAPH_ENDS,
+                               GTK_TYPE_INT, 1);
+
+  gtk_binding_entry_add_signal (binding_set, GDK_u, GDK_CONTROL_MASK,
+                               "delete_from_cursor", 2,
+                               GTK_TYPE_ENUM, GTK_DELETE_PARAGRAPHS,
+                               GTK_TYPE_INT, 1);
+
+  gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_MOD1_MASK,
+                               "delete_from_cursor", 2,
+                               GTK_TYPE_ENUM, GTK_DELETE_WHITESPACE,
+                               GTK_TYPE_INT, 1);
+  gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_MOD1_MASK,
+                               "insert_at_cursor", 1,
+                               GTK_TYPE_STRING, " ");
+
+  gtk_binding_entry_add_signal (binding_set, GDK_backslash, GDK_MOD1_MASK,
+                               "delete_from_cursor", 2,
+                               GTK_TYPE_ENUM, GTK_DELETE_WHITESPACE,
+                               GTK_TYPE_INT, 1);
+  
+  /* Cut/copy/paste */
+
+  gtk_binding_entry_add_signal (binding_set, GDK_x, GDK_CONTROL_MASK,
+                               "cut_clipboard", 0);
+
+  gtk_binding_entry_add_signal (binding_set, GDK_w, GDK_CONTROL_MASK,
+                               "cut_clipboard", 0);
+  
+  gtk_binding_entry_add_signal (binding_set, GDK_c, GDK_CONTROL_MASK,
+                               "copy_clipboard", 0);
+  
+  gtk_binding_entry_add_signal (binding_set, GDK_v, GDK_CONTROL_MASK,
+                               "paste_clipboard", 0);
 
+  gtk_binding_entry_add_signal (binding_set, GDK_y, GDK_CONTROL_MASK,
+                               "paste_clipboard", 0);
+
+  /* Overwrite */
+  gtk_binding_entry_add_signal (binding_set, GDK_Insert, 0,
+                               "toggle_overwrite", 0);
+  
   object_class->set_arg = gtk_entry_set_arg;
   object_class->get_arg = gtk_entry_get_arg;
 
@@ -290,22 +531,27 @@ gtk_entry_class_init (GtkEntryClass *class)
   widget_class->direction_changed = gtk_entry_direction_changed;
   widget_class->state_changed = gtk_entry_state_changed;
 
-  editable_class->insert_text = gtk_entry_insert_text;
-  editable_class->delete_text = gtk_entry_delete_text;
-  editable_class->changed = (void (*)(GtkEditable *)) entry_adjust_scroll;
-
-  editable_class->move_cursor = gtk_entry_move_cursor;
-  editable_class->move_word = gtk_entry_move_word;
-  editable_class->move_to_column = gtk_entry_move_to_column;
-
-  editable_class->kill_char = gtk_entry_kill_char;
-  editable_class->kill_word = gtk_entry_kill_word;
-  editable_class->kill_line = gtk_entry_kill_line;
+  class->insert_text = gtk_entry_real_insert_text;
+  class->delete_text = gtk_entry_real_delete_text;
+  class->move = gtk_entry_move;
+  class->insert = gtk_entry_insert;
+  class->delete = gtk_entry_delete;
+  class->cut_clipboard = gtk_entry_cut_clipboard;
+  class->copy_clipboard = gtk_entry_copy_clipboard;
+  class->paste_clipboard = gtk_entry_paste_clipboard;
+  class->toggle_overwrite = gtk_entry_toggle_overwrite;
+}
 
-  editable_class->update_text = gtk_entry_update_text;
-  editable_class->get_chars   = gtk_entry_get_chars;
-  editable_class->set_selection = gtk_entry_set_selection;
-  editable_class->set_position = gtk_entry_set_position_from_editable;
+static void
+gtk_entry_editable_init (GtkEditableClass *iface)
+{
+  iface->insert_text = gtk_entry_insert_text;
+  iface->delete_text = gtk_entry_delete_text;
+  iface->get_chars = gtk_entry_get_chars;
+  iface->set_selection_bounds = gtk_entry_set_selection_bounds;
+  iface->get_selection_bounds = gtk_entry_get_selection_bounds;
+  iface->set_position = gtk_entry_real_set_position;
+  iface->get_position = gtk_entry_get_position;
 }
 
 static void
@@ -313,12 +559,23 @@ gtk_entry_set_arg (GtkObject      *object,
                   GtkArg         *arg,
                   guint           arg_id)
 {
-  GtkEntry *entry;
-
-  entry = GTK_ENTRY (object);
+  GtkEntry *entry = GTK_ENTRY (object);
 
   switch (arg_id)
     {
+    case ARG_TEXT_POSITION:
+      gtk_editable_set_position (GTK_EDITABLE (object), GTK_VALUE_INT (*arg));
+      break;
+    case ARG_EDITABLE:
+      {
+       gboolean new_value = GTK_VALUE_BOOL (*arg) != 0;
+       if (new_value != entry->editable)
+         {
+           entry->editable = new_value;
+           gtk_entry_queue_draw (entry);
+         }
+      }
+      break;
     case ARG_MAX_LENGTH:
       gtk_entry_set_max_length (entry, GTK_VALUE_UINT (*arg));
       break;
@@ -341,11 +598,17 @@ gtk_entry_get_arg (GtkObject      *object,
 
   switch (arg_id)
     {
+    case ARG_TEXT_POSITION:
+      GTK_VALUE_INT (*arg) = entry->current_pos;
+      break;
+    case ARG_EDITABLE:
+      GTK_VALUE_BOOL (*arg) = entry->editable;
+      break;
     case ARG_MAX_LENGTH:
       GTK_VALUE_UINT (*arg) = entry->text_max_length;
       break;
     case ARG_VISIBILITY:
-      GTK_VALUE_BOOL (*arg) = GTK_EDITABLE (entry)->visible;
+      GTK_VALUE_BOOL (*arg) = entry->visible;
       break;
     default:
       arg->type = GTK_TYPE_INVALID;
@@ -358,20 +621,12 @@ gtk_entry_init (GtkEntry *entry)
 {
   GTK_WIDGET_SET_FLAGS (entry, GTK_CAN_FOCUS);
 
-  entry->text_area = NULL;
-  
   entry->text_size = MIN_SIZE;
   entry->text = g_malloc (entry->text_size);
   entry->text[0] = '\0';
-  
-  entry->text_length = 0;
-  entry->text_max_length = 0;
-  entry->n_bytes = 0;
-  entry->scroll_offset = 0;
-  entry->timer = 0;
-  entry->button = 0;
-  entry->ascent = 0;
-  entry->descent = 0;
+
+  entry->editable = TRUE;
+  entry->visible = TRUE;
 
   /* This object is completely private. No external entity can gain a reference
    * to it; so we create it here and destroy it in finalize().
@@ -380,124 +635,8 @@ gtk_entry_init (GtkEntry *entry)
   
   gtk_signal_connect (GTK_OBJECT (entry->im_context), "commit",
                      GTK_SIGNAL_FUNC (gtk_entry_commit_cb), entry);
-}
-
-GtkWidget*
-gtk_entry_new (void)
-{
-  return GTK_WIDGET (gtk_type_new (GTK_TYPE_ENTRY));
-}
-
-GtkWidget*
-gtk_entry_new_with_max_length (guint16 max)
-{
-  GtkEntry *entry;
-
-  entry = gtk_type_new (GTK_TYPE_ENTRY);
-  entry->text_max_length = max;
-
-  return GTK_WIDGET (entry);
-}
-
-void
-gtk_entry_set_text (GtkEntry *entry,
-                   const gchar *text)
-{
-  gint tmp_pos;
-
-  GtkEditable *editable;
-
-  g_return_if_fail (entry != NULL);
-  g_return_if_fail (GTK_IS_ENTRY (entry));
-  g_return_if_fail (text != NULL);
-
-  editable = GTK_EDITABLE (entry);
-  
-  gtk_entry_delete_text (GTK_EDITABLE(entry), 0, entry->text_length);
-
-  tmp_pos = 0;
-  gtk_editable_insert_text (editable, text, strlen (text), &tmp_pos);
-  editable->current_pos = tmp_pos;
-}
-
-void
-gtk_entry_append_text (GtkEntry *entry,
-                      const gchar *text)
-{
-  gint tmp_pos;
-
-  g_return_if_fail (entry != NULL);
-  g_return_if_fail (GTK_IS_ENTRY (entry));
-  g_return_if_fail (text != NULL);
-
-  tmp_pos = entry->text_length;
-  gtk_editable_insert_text (GTK_EDITABLE(entry), text, strlen (text), &tmp_pos);
-}
-
-void
-gtk_entry_prepend_text (GtkEntry *entry,
-                       const gchar *text)
-{
-  gint tmp_pos;
-
-  g_return_if_fail (entry != NULL);
-  g_return_if_fail (GTK_IS_ENTRY (entry));
-  g_return_if_fail (text != NULL);
-
-  tmp_pos = 0;
-  gtk_editable_insert_text (GTK_EDITABLE(entry), text, strlen (text), &tmp_pos);
-}
-
-void
-gtk_entry_set_position (GtkEntry *entry,
-                       gint      position)
-{
-  g_return_if_fail (entry != NULL);
-  g_return_if_fail (GTK_IS_ENTRY (entry));
-
-  if ((position == -1) || (position > entry->text_length))
-    GTK_EDITABLE(entry)->current_pos = entry->text_length;
-  else
-    GTK_EDITABLE(entry)->current_pos = position;
-  entry_adjust_scroll (entry);
-}
-
-static void
-gtk_entry_set_position_from_editable (GtkEditable *editable,
-                                     gint position)
-{
-  gtk_entry_set_position (GTK_ENTRY (editable), position);
-}
-
-void
-gtk_entry_set_visibility (GtkEntry *entry,
-                         gboolean visible)
-{
-  g_return_if_fail (entry != NULL);
-  g_return_if_fail (GTK_IS_ENTRY (entry));
-
-  GTK_EDITABLE (entry)->visible = visible ? TRUE : FALSE;
-  
-  gtk_entry_queue_draw (entry);
-}
-
-void
-gtk_entry_set_editable(GtkEntry *entry,
-                      gboolean  editable)
-{
-  g_return_if_fail (entry != NULL);
-  g_return_if_fail (GTK_IS_ENTRY (entry));
-
-  gtk_editable_set_editable (GTK_EDITABLE (entry), editable);
-}
-
-gchar*
-gtk_entry_get_text (GtkEntry *entry)
-{
-  g_return_val_if_fail (entry != NULL, NULL);
-  g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
-
-  return entry->text;
+  gtk_signal_connect (GTK_OBJECT (entry->im_context), "preedit_changed",
+                     GTK_SIGNAL_FUNC (gtk_entry_preedit_changed_cb), entry);
 }
 
 static void
@@ -509,13 +648,16 @@ gtk_entry_finalize (GObject *object)
 
   entry = GTK_ENTRY (object);
 
-  if (entry->layout)
-    g_object_unref (G_OBJECT (entry->layout));
+  if (entry->cached_layout)
+    g_object_unref (G_OBJECT (entry->cached_layout));
 
   gtk_object_unref (GTK_OBJECT (entry->im_context));
 
   if (entry->timer)
-    gtk_timeout_remove (entry->timer);
+    g_source_remove (entry->timer);
+
+  if (entry->recompute_idle)
+    g_source_remove (entry->recompute_idle);
 
   entry->text_size = 0;
 
@@ -559,10 +701,7 @@ gtk_entry_realize (GtkWidget *widget)
                            GDK_BUTTON_RELEASE_MASK |
                            GDK_BUTTON1_MOTION_MASK |
                            GDK_BUTTON3_MOTION_MASK |
-                           GDK_POINTER_MOTION_HINT_MASK |
-                           GDK_ENTER_NOTIFY_MASK |
-                           GDK_LEAVE_NOTIFY_MASK |
-                           GDK_KEY_PRESS_MASK);
+                           GDK_POINTER_MOTION_HINT_MASK);
   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
 
   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
@@ -572,7 +711,7 @@ gtk_entry_realize (GtkWidget *widget)
   attributes.y = widget->style->ythickness;
   attributes.width = widget->allocation.width - attributes.x * 2;
   attributes.height = requisition.height - attributes.y * 2;
-  attributes.cursor = entry->cursor = gdk_cursor_new (GDK_XTERM);
+  attributes.cursor = gdk_cursor_new (GDK_XTERM);
   attributes_mask |= GDK_WA_CURSOR;
 
   entry->text_area = gdk_window_new (widget->window, &attributes, attributes_mask);
@@ -585,12 +724,9 @@ gtk_entry_realize (GtkWidget *widget)
 
   gdk_window_show (entry->text_area);
 
-  if (editable->selection_start_pos != editable->selection_end_pos)
-    gtk_editable_claim_selection (editable, TRUE, GDK_CURRENT_TIME);
-
   gtk_im_context_set_client_window (entry->im_context, entry->text_area);
 
-  entry_adjust_scroll (entry);
+  gtk_entry_adjust_scroll (entry);
 }
 
 static void
@@ -610,52 +746,15 @@ gtk_entry_unrealize (GtkWidget *widget)
       gdk_window_set_user_data (entry->text_area, NULL);
       gdk_window_destroy (entry->text_area);
       entry->text_area = NULL;
-      gdk_cursor_destroy (entry->cursor);
-      entry->cursor = NULL;
     }
 
+  if (entry->popup_menu)
+    gtk_widget_destroy (entry->popup_menu);
+
   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
 }
 
-static void
-gtk_entry_draw_focus (GtkWidget *widget)
-{
-  gint width, height;
-  gint x, y;
-
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (GTK_IS_ENTRY (widget));
-
-  if (GTK_WIDGET_DRAWABLE (widget))
-    {
-      x = 0;
-      y = 0;
-      gdk_window_get_size (widget->window, &width, &height);
-
-      if (GTK_WIDGET_HAS_FOCUS (widget))
-       {
-         x += 1;
-         y += 1;
-         width -= 2;
-         height -= 2;
-       }
-
-      gtk_paint_shadow (widget->style, widget->window,
-                       GTK_STATE_NORMAL, GTK_SHADOW_IN,
-                       NULL, widget, "entry",
-                       x, y, width, height);
-
-      if (GTK_WIDGET_HAS_FOCUS (widget))
-       {
-          gdk_window_get_size (widget->window, &width, &height);
-          gtk_paint_focus (widget->style, widget->window, 
-                           NULL, widget, "entry",
-                           0, 0, width - 1, height - 1);
-       }
-    }
-}
-
 static void
 gtk_entry_size_request (GtkWidget      *widget,
                        GtkRequisition *requisition)
@@ -671,13 +770,11 @@ gtk_entry_size_request (GtkWidget      *widget,
 
   entry = GTK_ENTRY (widget);
   
-  gtk_entry_ensure_layout (entry);
-
   /* hackish for now, get metrics
    */
-  font = pango_context_load_font (pango_layout_get_context (entry->layout),
+  font = pango_context_load_font (gtk_widget_get_pango_context (widget),
                                  widget->style->font_desc);
-  lang = pango_context_get_lang (pango_layout_get_context (entry->layout));
+  lang = pango_context_get_lang (gtk_widget_get_pango_context (widget));
   pango_font_get_metrics (font, lang, &metrics);
   g_free (lang);
   
@@ -725,8 +822,7 @@ gtk_entry_size_allocate (GtkWidget     *widget,
                              allocation->width - widget->style->xthickness * 2,
                              requisition.height - widget->style->ythickness * 2);
 
-      /* And make sure the cursor is on screen */
-      entry_adjust_scroll (entry);
+      gtk_entry_recompute (entry);
     }
 }
 
@@ -757,76 +853,109 @@ gtk_entry_draw (GtkWidget    *widget,
     }
 }
 
-static gint
-gtk_entry_expose (GtkWidget      *widget,
-                 GdkEventExpose *event)
+static void
+gtk_entry_draw_focus (GtkWidget *widget)
 {
-  GtkEntry *entry;
-
-  g_return_val_if_fail (widget != NULL, FALSE);
-  g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE);
-  g_return_val_if_fail (event != NULL, FALSE);
+  gint width, height;
+  gint x, y;
 
-  entry = GTK_ENTRY (widget);
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_ENTRY (widget));
 
-  if (widget->window == event->window)
-    gtk_widget_draw_focus (widget);
-  else if (entry->text_area == event->window)
+  if (GTK_WIDGET_DRAWABLE (widget))
     {
-      gtk_entry_draw_text (GTK_ENTRY (widget));
-      gtk_entry_draw_cursor (GTK_ENTRY (widget));
-    }
+      x = 0;
+      y = 0;
+      gdk_window_get_size (widget->window, &width, &height);
 
-  return FALSE;
-}
+      if (GTK_WIDGET_HAS_FOCUS (widget))
+       {
+         x += 1;
+         y += 1;
+         width -= 2;
+         height -= 2;
+       }
 
-static gint
-gtk_entry_button_press (GtkWidget      *widget,
-                       GdkEventButton *event)
+      gtk_paint_shadow (widget->style, widget->window,
+                       GTK_STATE_NORMAL, GTK_SHADOW_IN,
+                       NULL, widget, "entry",
+                       x, y, width, height);
+
+      if (GTK_WIDGET_HAS_FOCUS (widget))
+       {
+          gdk_window_get_size (widget->window, &width, &height);
+          gtk_paint_focus (widget->style, widget->window, 
+                           NULL, widget, "entry",
+                           0, 0, width - 1, height - 1);
+       }
+    }
+}
+
+static gint
+gtk_entry_expose (GtkWidget      *widget,
+                 GdkEventExpose *event)
 {
   GtkEntry *entry;
-  GtkEditable *editable;
-  gint tmp_pos;
 
   g_return_val_if_fail (widget != NULL, FALSE);
   g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE);
   g_return_val_if_fail (event != NULL, FALSE);
 
-  if (ctext_atom == GDK_NONE)
-    ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE);
+  entry = GTK_ENTRY (widget);
+
+  if (widget->window == event->window)
+    gtk_widget_draw_focus (widget);
+  else if (entry->text_area == event->window)
+    {
+      gtk_entry_draw_text (GTK_ENTRY (widget));
+      gtk_entry_draw_cursor (GTK_ENTRY (widget));
+    }
+
+  return FALSE;
+}
+
+static gint
+gtk_entry_button_press (GtkWidget      *widget,
+                       GdkEventButton *event)
+{
+  GtkEntry *entry = GTK_ENTRY (widget);
+  GtkEditable *editable = GTK_EDITABLE (widget);
+  gint tmp_pos;
 
   entry = GTK_ENTRY (widget);
   editable = GTK_EDITABLE (widget);
   
-  if (entry->button && (event->button != entry->button))
+  if (event->window != entry->text_area ||
+      (entry->button && event->button != entry->button))
     return FALSE;
 
   entry->button = event->button;
   
   if (!GTK_WIDGET_HAS_FOCUS (widget))
     gtk_widget_grab_focus (widget);
-
+  
+  tmp_pos = gtk_entry_find_position (entry, event->x + entry->scroll_offset);
+    
   if (event->button == 1)
     {
       switch (event->type)
        {
        case GDK_BUTTON_PRESS:
-         gtk_grab_add (widget);
-
-         tmp_pos = gtk_entry_find_position (entry, event->x + entry->scroll_offset);
-         /* Set it now, so we display things right. We'll unset it
-          * later if things don't work out */
-         editable->has_selection = TRUE;
-         gtk_entry_set_selection (editable, tmp_pos, tmp_pos);
-         editable->current_pos = editable->selection_start_pos;
+         gtk_entry_reset_im_context (entry);
+         
+         entry->current_pos = tmp_pos;
+         entry->selection_bound = tmp_pos;
+
+         gtk_entry_recompute (entry);
+         
          break;
 
        case GDK_2BUTTON_PRESS:
-         gtk_select_word (entry, event->time);
+         gtk_entry_select_word (entry);
          break;
 
        case GDK_3BUTTON_PRESS:
-         gtk_select_line (entry, event->time);
+         gtk_entry_select_line (entry);
          break;
 
        default:
@@ -835,28 +964,17 @@ gtk_entry_button_press (GtkWidget      *widget,
 
       return TRUE;
     }
-  else if (event->type == GDK_BUTTON_PRESS)
+  else if (event->button == 2 && event->type == GDK_BUTTON_PRESS && entry->editable)
     {
-      if ((event->button == 2) && editable->editable)
-       {
-         if (editable->selection_start_pos == editable->selection_end_pos ||
-             editable->has_selection)
-           editable->current_pos = gtk_entry_find_position (entry, event->x + entry->scroll_offset);
-         gtk_selection_convert (widget, GDK_SELECTION_PRIMARY,
-                                ctext_atom, event->time);
-       }
-      else
-       {
-         gtk_grab_add (widget);
-
-         tmp_pos = gtk_entry_find_position (entry, event->x + entry->scroll_offset);
-         gtk_entry_set_selection (editable, tmp_pos, tmp_pos);
-         editable->has_selection = FALSE;
-         editable->current_pos = editable->selection_start_pos;
+      gtk_editable_select_region (editable, tmp_pos, tmp_pos);
+      gtk_entry_paste (entry, GDK_SELECTION_PRIMARY);
 
-         if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
-           gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, event->time);
-       }
+      return TRUE;
+    }
+  else if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
+    {
+      gtk_entry_popup_menu (entry, event);
+      entry->button = 0;       /* Don't wait for release, since the menu will gtk_grab_add */
 
       return TRUE;
     }
@@ -868,46 +986,20 @@ static gint
 gtk_entry_button_release (GtkWidget      *widget,
                          GdkEventButton *event)
 {
-  GtkEntry *entry;
-  GtkEditable *editable;
-
-  g_return_val_if_fail (widget != NULL, FALSE);
-  g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE);
-  g_return_val_if_fail (event != NULL, FALSE);
-
-  entry = GTK_ENTRY (widget);
-  editable = GTK_EDITABLE (widget);
+  GtkEntry *entry = GTK_ENTRY (widget);
+  GtkEditable *editable = GTK_EDITABLE (widget);
 
-  if (entry->button != event->button)
+  if (event->window != entry->text_area || entry->button != event->button)
     return FALSE;
 
   entry->button = 0;
   
   if (event->button == 1)
     {
-      gtk_grab_remove (widget);
-
-      editable->has_selection = FALSE;
-      if (editable->selection_start_pos != editable->selection_end_pos)
-       {
-         if (gtk_selection_owner_set (widget,
-                                      GDK_SELECTION_PRIMARY,
-                                      event->time))
-           editable->has_selection = TRUE;
-         else
-           gtk_entry_queue_draw (entry);
-       }
-      else
-       {
-         if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
-           gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, event->time);
-       }
+      gint tmp_pos;
 
-      return TRUE;
-    }
-  else if (event->button == 3)
-    {
-      gtk_grab_remove (widget);
+      tmp_pos = gtk_entry_find_position (entry, event->x + entry->scroll_offset);
+      gtk_editable_select_region (editable, entry->selection_bound, tmp_pos);
 
       return TRUE;
     }
@@ -919,27 +1011,23 @@ static gint
 gtk_entry_motion_notify (GtkWidget      *widget,
                         GdkEventMotion *event)
 {
-  GtkEntry *entry;
-  gint x;
-
-  g_return_val_if_fail (widget != NULL, FALSE);
-  g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE);
-  g_return_val_if_fail (event != NULL, FALSE);
-
-  entry = GTK_ENTRY (widget);
+  GtkEntry *entry = GTK_ENTRY (widget);
+  gint tmp_pos;
 
-  if (entry->button == 0)
+  if (event->window != entry->text_area || entry->button != 1)
     return FALSE;
 
-  x = event->x;
   if (event->is_hint || (entry->text_area != event->window))
-    gdk_window_get_pointer (entry->text_area, &x, NULL, NULL);
+    gdk_window_get_pointer (entry->text_area, NULL, NULL, NULL);
 
-  GTK_EDITABLE(entry)->selection_end_pos = gtk_entry_find_position (entry, x + entry->scroll_offset);
-  GTK_EDITABLE(entry)->current_pos = GTK_EDITABLE(entry)->selection_end_pos;
-  entry_adjust_scroll (entry);
-  gtk_entry_queue_draw (entry);
+  tmp_pos = gtk_entry_find_position (entry, event->x + entry->scroll_offset);
 
+  if (tmp_pos != entry->current_pos)
+    {
+      entry->current_pos = tmp_pos;
+      gtk_entry_recompute (entry);
+    }
+      
   return TRUE;
 }
 
@@ -947,230 +1035,644 @@ static gint
 gtk_entry_key_press (GtkWidget   *widget,
                     GdkEventKey *event)
 {
-  GtkEntry *entry;
-  GtkEditable *editable;
+  GtkEntry *entry = GTK_ENTRY (widget);
 
-  gint return_val;
-  gint key;
-  guint initial_pos;
-  gint extend_selection;
-  gint extend_start;
+  if (!entry->editable)
+    return FALSE;
 
+  /* Activate key bindings
+   */
+  if (GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event))
+    return TRUE;
+
+  /* Not bound, pass to input method
+   */
+  entry->need_im_reset = TRUE;
+  return gtk_im_context_filter_keypress (entry->im_context, event);
+}
+
+static gint
+gtk_entry_focus_in (GtkWidget     *widget,
+                   GdkEventFocus *event)
+{
   g_return_val_if_fail (widget != NULL, FALSE);
   g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE);
   g_return_val_if_fail (event != NULL, FALSE);
 
-  entry = GTK_ENTRY (widget);
-  editable = GTK_EDITABLE (widget);
-  return_val = FALSE;
+  GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
+  gtk_widget_draw_focus (widget);
+  gtk_entry_queue_draw (GTK_ENTRY (widget));
+  
+  GTK_ENTRY (widget)->need_im_reset = TRUE;
+  gtk_im_context_focus_in (GTK_ENTRY (widget)->im_context);
 
-  if(editable->editable == FALSE)
-    return FALSE;
+  return FALSE;
+}
 
-  initial_pos = editable->current_pos;
+static gint
+gtk_entry_focus_out (GtkWidget     *widget,
+                    GdkEventFocus *event)
+{
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
 
-  extend_selection = event->state & GDK_SHIFT_MASK;
-  extend_start = FALSE;
+  GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
+  gtk_widget_draw_focus (widget);
+  gtk_entry_queue_draw (GTK_ENTRY (widget));
 
-  if (extend_selection)
+  GTK_ENTRY (widget)->need_im_reset = TRUE;
+  gtk_im_context_focus_out (GTK_ENTRY (widget)->im_context);
+
+  return FALSE;
+}
+
+static void 
+gtk_entry_direction_changed (GtkWidget        *widget,
+                            GtkTextDirection  previous_dir)
+{
+  GtkEntry *entry = GTK_ENTRY (widget);
+
+  gtk_entry_recompute (entry);
+      
+  GTK_WIDGET_CLASS (parent_class)->direction_changed (widget, previous_dir);
+}
+
+static void
+gtk_entry_state_changed (GtkWidget      *widget,
+                        GtkStateType    previous_state)
+{
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_ENTRY (widget));
+
+  if (GTK_WIDGET_REALIZED (widget))
+    {
+      gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
+      gdk_window_set_background (GTK_ENTRY (widget)->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]);
+    }
+
+  gtk_widget_queue_clear (widget);
+}
+
+/* GtkEditable method implementations
+ */
+static void
+gtk_entry_insert_text (GtkEditable *editable,
+                      const gchar *new_text,
+                      gint         new_text_length,
+                      gint        *position)
+{
+  GtkEntry *entry = GTK_ENTRY (editable);
+  gchar buf[64];
+  gchar *text;
+
+  if (*position < 0 || *position > entry->text_length)
+    *position = entry->text_length;
+  
+  g_object_ref (G_OBJECT (editable));
+  
+  if (new_text_length <= 63)
+    text = buf;
+  else
+    text = g_new (gchar, new_text_length + 1);
+
+  text[new_text_length] = '\0';
+  strncpy (text, new_text, new_text_length);
+
+  gtk_signal_emit (GTK_OBJECT (editable), signals[INSERT_TEXT], text, new_text_length, position);
+  gtk_signal_emit (GTK_OBJECT (editable), signals[CHANGED]);
+
+  if (new_text_length > 63)
+    g_free (text);
+
+  g_object_unref (G_OBJECT (editable));
+}
+
+static void
+gtk_entry_delete_text (GtkEditable *editable,
+                      gint         start_pos,
+                      gint         end_pos)
+{
+  GtkEntry *entry = GTK_ENTRY (editable);
+
+  if (end_pos < 0 || end_pos > entry->text_length)
+    end_pos = entry->text_length;
+  if (start_pos < 0)
+    start_pos = 0;
+  if (start_pos > end_pos)
+    start_pos = end_pos;
+  
+  g_object_ref (G_OBJECT (editable));
+
+  gtk_signal_emit (GTK_OBJECT (editable), signals[DELETE_TEXT], start_pos, end_pos);
+  gtk_signal_emit (GTK_OBJECT (editable), signals[CHANGED]);
+
+  g_object_unref (G_OBJECT (editable));
+}
+
+static gchar *    
+gtk_entry_get_chars      (GtkEditable   *editable,
+                         gint           start_pos,
+                         gint           end_pos)
+{
+  GtkEntry *entry;
+  gint start_index, end_index;
+  
+  g_return_val_if_fail (editable != NULL, NULL);
+  g_return_val_if_fail (GTK_IS_ENTRY (editable), NULL);
+
+  entry = GTK_ENTRY (editable);
+
+  if (end_pos < 0)
+    end_pos = entry->text_length;
+
+  start_pos = MIN (entry->text_length, start_pos);
+  end_pos = MIN (entry->text_length, end_pos);
+
+  start_index = g_utf8_offset_to_pointer (entry->text, start_pos) - entry->text;
+  end_index = g_utf8_offset_to_pointer (entry->text, end_pos) - entry->text;
+
+  return g_strndup (entry->text + start_index, end_index - start_index);
+}
+
+static void
+gtk_entry_real_set_position (GtkEditable *editable,
+                            gint         position)
+{
+  GtkEntry *entry = GTK_ENTRY (editable);
+  
+  if (position < 0 || position > entry->text_length)
+    position = entry->text_length;
+
+  if (position != entry->current_pos)
+    {
+      gtk_entry_reset_im_context (entry);
+
+      entry->current_pos = entry->selection_bound = position;
+      gtk_entry_recompute (entry);
+    }
+}
+
+static gint
+gtk_entry_get_position (GtkEditable *editable)
+{
+  return GTK_ENTRY (editable)->current_pos;
+}
+
+static void
+gtk_entry_set_selection_bounds (GtkEditable *editable,
+                               gint         start,
+                               gint         end)
+{
+  GtkEntry *entry = GTK_ENTRY (editable);
+
+  if (start < 0)
+    start = entry->text_length;
+  if (end < 0)
+    end = entry->text_length;
+  
+  gtk_entry_reset_im_context (entry);
+
+  entry->selection_bound = MIN (start, entry->text_length);
+  entry->current_pos = MIN (end, entry->text_length);
+
+  gtk_entry_update_primary_selection (entry);
+  
+  gtk_entry_recompute (entry);
+}
+
+static gboolean
+gtk_entry_get_selection_bounds (GtkEditable *editable,
+                               gint        *start,
+                               gint        *end)
+{
+  GtkEntry *entry = GTK_ENTRY (editable);
+
+  *start = entry->selection_bound;
+  *end = entry->current_pos;
+
+  return (entry->selection_bound != entry->current_pos);
+}
+
+static void 
+gtk_entry_style_set    (GtkWidget      *widget,
+                        GtkStyle       *previous_style)
+{
+  GtkEntry *entry = GTK_ENTRY (widget);
+
+  if (previous_style && GTK_WIDGET_REALIZED (widget))
     {
-      if (editable->selection_start_pos == editable->selection_end_pos)
+      gtk_entry_recompute (entry);
+
+      gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
+      gdk_window_set_background (entry->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]);
+    }
+}
+
+/* Default signal handlers
+ */
+static void
+gtk_entry_real_insert_text (GtkEntry    *entry,
+                           const gchar *new_text,
+                           gint         new_text_length,
+                           gint        *position)
+{
+  gint index;
+  gint n_chars;
+
+  if (new_text_length < 0)
+    new_text_length = strlen (new_text);
+
+  n_chars = g_utf8_strlen (new_text, new_text_length);
+  if (entry->text_max_length > 0 && n_chars + entry->text_length > entry->text_max_length)
+    {
+      gdk_beep ();
+      n_chars = entry->text_max_length - entry->text_length;
+    }
+
+  if (new_text_length + entry->n_bytes + 1 > entry->text_size)
+    {
+      while (new_text_length + entry->n_bytes + 1 > entry->text_size)
        {
-         editable->selection_start_pos = editable->current_pos;
-         editable->selection_end_pos = editable->current_pos;
+         if (entry->text_size == 0)
+           entry->text_size = MIN_SIZE;
+         else
+           {
+             if (2 * (guint)entry->text_size < MAX_SIZE &&
+                 2 * (guint)entry->text_size > entry->text_size)
+               entry->text_size *= 2;
+             else
+               {
+                 entry->text_size = MAX_SIZE;
+                 new_text_length = entry->text_size - new_text_length - 1;
+                 break;
+               }
+           }
        }
+
+      entry->text = g_realloc (entry->text, entry->text_size);
+    }
+
+  index = g_utf8_offset_to_pointer (entry->text, *position) - entry->text;
+
+  g_memmove (entry->text + index + new_text_length, entry->text + index, entry->n_bytes - index);
+  memcpy (entry->text + index, new_text, new_text_length);
+
+  entry->n_bytes += new_text_length;
+  entry->text_length += n_chars;
+
+  /* NUL terminate for safety and convenience */
+  entry->text[entry->n_bytes] = '\0';
+  
+  if (entry->current_pos > *position)
+    entry->current_pos += n_chars;
+  
+  if (entry->selection_bound > *position)
+    entry->selection_bound += n_chars;
+
+  *position += n_chars;
+
+  gtk_entry_recompute (entry);
+}
+
+static void
+gtk_entry_real_delete_text (GtkEntry *entry,
+                           gint      start_pos,
+                           gint      end_pos)
+{
+  if (start_pos < 0)
+    start_pos = 0;
+  if (end_pos < 0 || end_pos > entry->text_length)
+    end_pos = entry->text_length;
+  
+  if (start_pos < end_pos)
+    {
+      gint start_index = g_utf8_offset_to_pointer (entry->text, start_pos) - entry->text;
+      gint end_index = g_utf8_offset_to_pointer (entry->text, end_pos) - entry->text;
+
+      g_memmove (entry->text + start_index, entry->text + end_index, entry->n_bytes - end_index);
+      entry->text_length -= (end_pos - start_pos);
+      entry->n_bytes -= (end_index - start_index);
       
-      extend_start = (editable->current_pos == editable->selection_start_pos);
+      if (entry->current_pos > start_pos)
+       entry->current_pos -= MIN (entry->current_pos, end_pos) - start_pos;
+
+      if (entry->selection_bound > start_pos)
+       entry->selection_bound -= MIN (entry->selection_bound, end_pos) - start_pos;
     }
 
-  switch (event->keyval)
+  /* We might have deleted the selection
+   */
+  gtk_entry_update_primary_selection (entry);
+
+  gtk_entry_recompute (entry);
+}
+
+
+static void
+gtk_entry_move (GtkEntry       *entry,
+               GtkMovementStep step,
+               gint            count,
+               gboolean        extend_selection)
+{
+  gint new_pos = entry->current_pos;
+
+  gtk_entry_reset_im_context (entry);
+  
+  switch (step)
     {
-    case GDK_BackSpace:
-      return_val = TRUE;
-      if (event->state & GDK_CONTROL_MASK)
-       gtk_delete_backward_word (entry);
-      else
-       gtk_delete_backward_character (entry);
+    case GTK_MOVEMENT_CHARS:
+      new_pos = CLAMP (new_pos + count, 0, entry->text_length);
       break;
-    case GDK_Clear:
-      return_val = TRUE;
-      gtk_delete_line (entry);
+    case GTK_MOVEMENT_POSITIONS:
+      new_pos = gtk_entry_move_visually (entry, new_pos, count);
       break;
-    case GDK_Insert:
-      return_val = TRUE;
-      if (event->state & GDK_SHIFT_MASK)
+    case GTK_MOVEMENT_WORDS:
+      while (count > 0)
        {
-         extend_selection = FALSE;
-         gtk_editable_paste_clipboard (editable);
-       }
-      else if (event->state & GDK_CONTROL_MASK)
-       {
-         gtk_editable_copy_clipboard (editable);
+         new_pos = gtk_entry_move_forward_word (entry, new_pos);
+         count--;
        }
-      else
+      while (count < 0)
        {
-         /* gtk_toggle_insert(entry) -- IMPLEMENT */
+         new_pos = gtk_entry_move_backward_word (entry, new_pos);
+         count++;
        }
       break;
-    case GDK_Delete:
-      return_val = TRUE;
-      if (event->state & GDK_CONTROL_MASK)
-       gtk_delete_forward_word (entry);
-      else if (event->state & GDK_SHIFT_MASK)
-       {
-         extend_selection = FALSE;
-         gtk_editable_cut_clipboard (editable);
-       }
-      else
-       gtk_delete_forward_character (entry);
+    case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
+    case GTK_MOVEMENT_PARAGRAPH_ENDS:
+    case GTK_MOVEMENT_BUFFER_ENDS:
+      new_pos = count < 0 ? 0 : entry->text_length;
       break;
-    case GDK_Home:
-      return_val = TRUE;
-      gtk_move_beginning_of_line (entry);
+    case GTK_MOVEMENT_DISPLAY_LINES:
+    case GTK_MOVEMENT_PARAGRAPHS:
+    case GTK_MOVEMENT_PAGES:
       break;
-    case GDK_End:
-      return_val = TRUE;
-      gtk_move_end_of_line (entry);
+    }
+
+  if (extend_selection)
+    gtk_editable_select_region (GTK_EDITABLE (entry), entry->selection_bound, new_pos);
+  else
+    gtk_editable_set_position (GTK_EDITABLE (entry), new_pos);
+}
+
+static void
+gtk_entry_insert (GtkEntry    *entry,
+                 const gchar *str)
+{
+  GtkEditable *editable = GTK_EDITABLE (entry);
+  gint pos = entry->current_pos;
+
+  gtk_entry_reset_im_context (entry);
+
+  gtk_editable_insert_text (editable, str, -1, &pos);
+  gtk_editable_set_position (editable, pos);
+}
+
+static void
+gtk_entry_delete (GtkEntry       *entry,
+                 GtkDeleteType   type,
+                 gint            count)
+{
+  GtkEditable *editable = GTK_EDITABLE (entry);
+  gint start_pos = entry->current_pos;
+  gint end_pos = entry->current_pos;
+  
+  gtk_entry_reset_im_context (entry);
+
+  if (!entry->editable)
+    return;
+
+  if (entry->selection_bound != entry->current_pos)
+    {
+      gtk_editable_delete_selection (editable);
+      return;
+    }
+  
+  switch (type)
+    {
+    case GTK_DELETE_CHARS:
+      end_pos = entry->current_pos + count;
+      gtk_editable_delete_text (editable, MIN (start_pos, end_pos), MAX (start_pos, end_pos));
       break;
-    case GDK_Left:
-      return_val = TRUE;
-      if (event->state & GDK_CONTROL_MASK)
-       gtk_move_backward_word (entry);
-      else
-       gtk_move_backward_character (entry);
+    case GTK_DELETE_WORDS:
+      if (count < 0)
+       {
+         /* Move to end of current word, or if not on a word, end of previous word */
+         end_pos = gtk_entry_move_backward_word (entry, end_pos);
+         end_pos = gtk_entry_move_forward_word (entry, end_pos);
+       }
+      else if (count > 0)
+       {
+         /* Move to beginning of current word, or if not on a word, begining of next word */
+         start_pos = gtk_entry_move_forward_word (entry, start_pos);
+         start_pos = gtk_entry_move_backward_word (entry, start_pos);
+       }
+       
+      /* Fall through */
+    case GTK_DELETE_WORD_ENDS:
+      while (count < 0)
+       {
+         start_pos = gtk_entry_move_backward_word (entry, start_pos);
+         count++;
+       }
+      while (count > 0)
+       {
+         end_pos = gtk_entry_move_forward_word (entry, end_pos);
+         count--;
+       }
+      gtk_editable_delete_text (editable, start_pos, end_pos);
       break;
-    case GDK_Right:
-      return_val = TRUE;
-      if (event->state & GDK_CONTROL_MASK)
-       gtk_move_forward_word (entry);
+    case GTK_DELETE_DISPLAY_LINE_ENDS:
+    case GTK_DELETE_PARAGRAPH_ENDS:
+      if (count < 0)
+       gtk_editable_delete_text (editable, 0, entry->current_pos);
       else
-       gtk_move_forward_character (entry);
+       gtk_editable_delete_text (editable, entry->current_pos, -1);
       break;
-    case GDK_Return:
-      return_val = TRUE;
-      gtk_widget_activate (widget);
+    case GTK_DELETE_DISPLAY_LINES:
+    case GTK_DELETE_PARAGRAPHS:
+      gtk_editable_delete_text (editable, 0, -1);  
       break;
-    /* The next two keys should not be inserted literally. Any others ??? */
-    case GDK_Tab:
-    case GDK_Escape:
+    case GTK_DELETE_WHITESPACE:
+      gtk_entry_delete_whitespace (entry);
       break;
-    default:
-      if ((event->keyval >= 0x20) && (event->keyval <= 0xFF))
-       {
-         key = event->keyval;
-
-         if (event->state & GDK_CONTROL_MASK)
-           {
-             if ((key >= 'A') && (key <= 'Z'))
-               key -= 'A' - 'a';
+    }
+}
 
-             if ((key >= 'a') && (key <= 'z') && control_keys[key - 'a'])
-               {
-                 (* control_keys[key - 'a']) (editable, event->time);
-                 return_val = TRUE;
-               }
-             break;
-           }
-         else if (event->state & GDK_MOD1_MASK)
-           {
-             if ((key >= 'A') && (key <= 'Z'))
-               key -= 'A' - 'a';
+static void
+gtk_entry_copy_clipboard (GtkEntry *entry)
+{
+  GtkEditable *editable = GTK_EDITABLE (entry);
+  gint start, end;
 
-             if ((key >= 'a') && (key <= 'z') && alt_keys[key - 'a'])
-               {
-                 (* alt_keys[key - 'a']) (editable, event->time);
-                 return_val = TRUE;
-               }
-             break;
-           }
-       }
-      gtk_im_context_filter_keypress (entry->im_context, event);
-      
-      break;
+  if (gtk_editable_get_selection_bounds (editable, &start, &end))
+    {
+      gchar *str = gtk_entry_get_public_chars (entry, start, end);
+      gtk_clipboard_set_text (gtk_clipboard_get (GDK_NONE), str, -1);
+      g_free (str);
     }
+}
 
-  /* since we emit signals from within the above code,
-   * the widget might already be destroyed or at least
-   * unrealized.
-   */
-  if (GTK_WIDGET_REALIZED (editable) &&
-      return_val && (editable->current_pos != initial_pos))
-    {
-      if (extend_selection)
-       {
-         if (editable->current_pos < editable->selection_start_pos)
-           editable->selection_start_pos = editable->current_pos;
-         else if (editable->current_pos > editable->selection_end_pos)
-           editable->selection_end_pos = editable->current_pos;
-         else
-           {
-             if (extend_start)
-               editable->selection_start_pos = editable->current_pos;
-             else
-               editable->selection_end_pos = editable->current_pos;
-           }
-       }
-      else
-       {
-         editable->selection_start_pos = 0;
-         editable->selection_end_pos = 0;
-       }
+static void
+gtk_entry_cut_clipboard (GtkEntry *entry)
+{
+  GtkEditable *editable = GTK_EDITABLE (entry);
+  gint start, end;
+
+  gtk_entry_copy_clipboard (entry);
+  if (gtk_editable_get_selection_bounds (editable, &start, &end))
+    gtk_editable_delete_text (editable, start, end);
+}
+
+static void
+gtk_entry_paste_clipboard (GtkEntry *entry)
+{
+  gtk_entry_paste (entry, GDK_NONE);
+}
+
+static void
+gtk_entry_toggle_overwrite (GtkEntry *entry)
+{
+  entry->overwrite_mode = !entry->overwrite_mode;
+}
+
+/* IM Context Callbacks
+ */
+
+static void
+gtk_entry_commit_cb (GtkIMContext *context,
+                    const gchar  *str,
+                    GtkEntry     *entry)
+{
+  GtkEditable *editable = GTK_EDITABLE (entry);
+  gint tmp_pos = entry->current_pos;
+
+  gtk_editable_insert_text (editable, str, strlen (str), &tmp_pos);
+  gtk_editable_set_position (editable, tmp_pos);
+}
+
+static void 
+gtk_entry_preedit_changed_cb (GtkIMContext *context,
+                             GtkEntry     *entry)
+{
+  gchar *preedit_string;
+  gint cursor_pos;
+  
+  gtk_im_context_get_preedit_string (entry->im_context,
+                                    &preedit_string, NULL,
+                                    &cursor_pos);
+  entry->preedit_length = strlen (preedit_string);
+  cursor_pos = CLAMP (cursor_pos, 0, g_utf8_strlen (preedit_string, -1));
+  cursor_pos = g_utf8_offset_to_pointer (preedit_string, cursor_pos) - preedit_string;
+  g_free (preedit_string);
+
+  gtk_entry_recompute (entry);
+}
+
+/* Internal functions
+ */
 
-      gtk_editable_claim_selection (editable,
-                                   editable->selection_start_pos != editable->selection_end_pos,
-                                   event->time);
-      
-      entry_adjust_scroll (entry);
-      gtk_entry_queue_draw (entry);
+static void
+gtk_entry_reset_layout (GtkEntry *entry)
+{
+  if (entry->cached_layout)
+    {
+      g_object_unref (G_OBJECT (entry->cached_layout));
+      entry->cached_layout = NULL;
     }
-
-  return return_val;
 }
 
-static gint
-gtk_entry_focus_in (GtkWidget     *widget,
-                   GdkEventFocus *event)
+static gboolean
+recompute_idle_func (gpointer data)
 {
-  g_return_val_if_fail (widget != NULL, FALSE);
-  g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE);
-  g_return_val_if_fail (event != NULL, FALSE);
+  GtkEntry *entry = GTK_ENTRY (data);
 
-  GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
-  gtk_widget_draw_focus (widget);
-  gtk_entry_queue_draw (GTK_ENTRY (widget));
-  
-  gtk_im_context_focus_in (GTK_ENTRY (widget)->im_context);
+  gtk_entry_adjust_scroll (entry);
+  gtk_entry_queue_draw (entry);
 
+  entry->recompute_idle = FALSE;
+  
   return FALSE;
 }
 
-static gint
-gtk_entry_focus_out (GtkWidget     *widget,
-                    GdkEventFocus *event)
+static void
+gtk_entry_recompute (GtkEntry *entry)
 {
-  g_return_val_if_fail (widget != NULL, FALSE);
-  g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE);
-  g_return_val_if_fail (event != NULL, FALSE);
+  gtk_entry_reset_layout (entry);
 
-  GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
-  gtk_widget_draw_focus (widget);
-  gtk_entry_queue_draw (GTK_ENTRY (widget));
+  if (!entry->recompute_idle)
+    {
+      entry->recompute_idle = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 15, /* between resize and redraw */
+                                              recompute_idle_func, entry, NULL); 
+    }
+}
 
-  gtk_im_context_focus_out (GTK_ENTRY (widget)->im_context);
+static PangoLayout *
+gtk_entry_create_layout (GtkEntry *entry,
+                        gboolean  include_preedit)
+{
+  PangoLayout *layout = gtk_widget_create_pango_layout (GTK_WIDGET (entry), NULL);
+  PangoAttrList *tmp_attrs = pango_attr_list_new ();
+  
+  gchar *preedit_string = NULL;
+  gint preedit_length = 0;
+  PangoAttrList *preedit_attrs = NULL;
 
-  return FALSE;
+  if (include_preedit)
+    {
+      gtk_im_context_get_preedit_string (entry->im_context,
+                                        &preedit_string, &preedit_attrs, NULL);
+      preedit_length = entry->preedit_length;
+    }
+
+  if (preedit_length)
+    {
+      GString *tmp_string = g_string_new (NULL);
+      
+      gint cursor_index = g_utf8_offset_to_pointer (entry->text, entry->current_pos) - entry->text;
+      
+      g_string_prepend_len (tmp_string, entry->text, entry->n_bytes);
+      g_string_insert (tmp_string, cursor_index, preedit_string);
+      pango_layout_set_text (layout, tmp_string->str, tmp_string->len);
+      
+      pango_attr_list_splice (tmp_attrs, preedit_attrs,
+                             cursor_index, entry->preedit_length);
+      
+      g_string_free (tmp_string, TRUE);
+
+    }
+  else
+    pango_layout_set_text (layout, entry->text, entry->n_bytes);
+
+  pango_layout_set_attributes (layout, tmp_attrs);
+
+  if (preedit_string)
+    g_free (preedit_string);
+  if (preedit_attrs)
+    pango_attr_list_unref (preedit_attrs);
+      
+  pango_attr_list_unref (tmp_attrs);
+
+  return layout;
 }
 
-static void
-gtk_entry_ensure_layout (GtkEntry *entry)
+static PangoLayout *
+gtk_entry_get_layout (GtkEntry *entry,
+                     gboolean  include_preedit)
 {
-  GtkWidget *widget = GTK_WIDGET (entry);
-  
-  if (!entry->layout)
+  if (entry->preedit_length > 0 &&
+      !include_preedit != !entry->cache_includes_preedit)
+    gtk_entry_reset_layout (entry);
+
+  if (!entry->cached_layout)
     {
-      entry->layout = gtk_widget_create_pango_layout (widget, NULL);
-      pango_layout_set_text (entry->layout, entry->text, entry->n_bytes);
+      entry->cached_layout = gtk_entry_create_layout (entry, include_preedit);
+      entry->cache_includes_preedit = include_preedit;
     }
+  
+  g_object_ref (G_OBJECT (entry->cached_layout));
+  return entry->cached_layout;
 }
 
 static void
@@ -1178,15 +1680,16 @@ gtk_entry_draw_text (GtkEntry *entry)
 {
   GtkWidget *widget;
   PangoLayoutLine *line;
-  GtkEditable *editable = GTK_EDITABLE (entry);
   
   g_return_if_fail (entry != NULL);
   g_return_if_fail (GTK_IS_ENTRY (entry));
 
   if (GTK_WIDGET_DRAWABLE (entry))
     {
+      PangoLayout *layout = gtk_entry_get_layout (entry, TRUE);
       PangoRectangle logical_rect;
       gint area_width, area_height;
+      gint start_pos, end_pos;
       gint y_pos;
 
       gdk_window_get_size (entry->text_area, &area_width, &area_height);
@@ -1199,9 +1702,7 @@ gtk_entry_draw_text (GtkEntry *entry)
                          NULL, widget, "entry_bg", 
                          0, 0, area_width, area_height);
       
-      gtk_entry_ensure_layout (entry);
-      
-      line = pango_layout_get_lines (entry->layout)->data;
+      line = pango_layout_get_lines (layout)->data;
       pango_layout_line_get_extents (line, NULL, &logical_rect);
 
       /* Align primarily for locale's ascent/descent */
@@ -1220,17 +1721,14 @@ gtk_entry_draw_text (GtkEntry *entry)
 
       gdk_draw_layout (entry->text_area, widget->style->text_gc [widget->state], 
                       INNER_BORDER - entry->scroll_offset, y_pos,
-                      entry->layout);
+                      layout);
 
-      if (editable->selection_start_pos != editable->selection_end_pos)
+      if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start_pos, &end_pos))
        {
          gint *ranges;
          gint n_ranges, i;
-         gint start_index = g_utf8_offset_to_pointer (entry->text,
-                                                      MIN (editable->selection_start_pos, editable->selection_end_pos)) - entry->text;
-         gint end_index = g_utf8_offset_to_pointer (entry->text,
-                                                    MAX (editable->selection_start_pos, editable->selection_end_pos)) - entry->text;
-         GtkStateType selected_state = editable->has_selection ? GTK_STATE_SELECTED : GTK_STATE_ACTIVE;
+         gint start_index = g_utf8_offset_to_pointer (entry->text, start_pos) - entry->text;
+         gint end_index = g_utf8_offset_to_pointer (entry->text, end_pos) - entry->text;
          GdkRegion *clip_region = gdk_region_new ();
 
          pango_layout_line_get_x_ranges (line, start_index, end_index, &ranges, &n_ranges);
@@ -1244,21 +1742,23 @@ gtk_entry_draw_text (GtkEntry *entry)
              rect.width = (ranges[2*i + 1] - ranges[2*i]) / PANGO_SCALE;
              rect.height = logical_rect.height / PANGO_SCALE;
              
-             gdk_draw_rectangle (entry->text_area, widget->style->bg_gc [selected_state], TRUE,
+             gdk_draw_rectangle (entry->text_area, widget->style->bg_gc [GTK_STATE_SELECTED], TRUE,
                                  rect.x, rect.y, rect.width, rect.height);
 
              gdk_region_union_with_rect (clip_region, &rect);
            }
 
-         gdk_gc_set_clip_region (widget->style->fg_gc [selected_state], clip_region);
-         gdk_draw_layout (entry->text_area, widget->style->fg_gc [selected_state], 
+         gdk_gc_set_clip_region (widget->style->fg_gc [GTK_STATE_SELECTED], clip_region);
+         gdk_draw_layout (entry->text_area, widget->style->fg_gc [GTK_STATE_SELECTED], 
                           INNER_BORDER - entry->scroll_offset, y_pos,
-                          entry->layout);
-         gdk_gc_set_clip_region (widget->style->fg_gc [selected_state], NULL);
+                          layout);
+         gdk_gc_set_clip_region (widget->style->fg_gc [GTK_STATE_SELECTED], NULL);
          
          gdk_region_destroy (clip_region);
          g_free (ranges);
        }
+
+      g_object_unref (G_OBJECT (layout));
     }
 }
 
@@ -1271,10 +1771,9 @@ gtk_entry_draw_cursor (GtkEntry *entry)
   if (GTK_WIDGET_DRAWABLE (entry))
     {
       GtkWidget *widget = GTK_WIDGET (entry);
-      GtkEditable *editable = GTK_EDITABLE (entry);
 
       if (GTK_WIDGET_HAS_FOCUS (widget) &&
-         (editable->selection_start_pos == editable->selection_end_pos))
+         (entry->selection_bound == entry->current_pos))
        {
          gint xoffset = INNER_BORDER - entry->scroll_offset;
          gint strong_x, weak_x;
@@ -1308,40 +1807,47 @@ gtk_entry_queue_draw (GtkEntry *entry)
       GdkRectangle rect = { 0 };
 
       gdk_window_get_size (entry->text_area, &rect.width, &rect.height);
-      gdk_window_invalidate_rect (entry->text_area, &rect, 0);
+      gdk_window_invalidate_rect (entry->text_area, &rect, FALSE);
     }
 }
 
-#if 0
-static gint
-gtk_entry_timer (gpointer data)
+static void
+gtk_entry_reset_im_context (GtkEntry *entry)
 {
-  GtkEntry *entry;
+  if (entry->need_im_reset)
+    entry->need_im_reset = 0;
 
-  GDK_THREADS_ENTER ();
-
-  entry = GTK_ENTRY (data);
-  entry->timer = 0;
-
-  GDK_THREADS_LEAVE ();
-
-  return FALSE;
+  gtk_im_context_reset (entry->im_context);
 }
-#endif
 
 static gint
 gtk_entry_find_position (GtkEntry *entry,
                         gint      x)
 {
+  PangoLayout *layout;
   PangoLayoutLine *line;
   gint index;
   gint pos;
   gboolean trailing;
+  gint cursor_index = g_utf8_offset_to_pointer (entry->text, entry->current_pos) - entry->text;
   
-  gtk_entry_ensure_layout (entry);
-
-  line = pango_layout_get_lines (entry->layout)->data;
+  layout = gtk_entry_get_layout (entry, TRUE);
+  
+  line = pango_layout_get_lines (layout)->data;
   pango_layout_line_x_to_index (line, x * PANGO_SCALE, &index, &trailing);
+  
+  g_object_unref (G_OBJECT (layout));
+
+  if (index >= cursor_index && entry->preedit_length)
+    {
+      if (index >= cursor_index + entry->preedit_length)
+       index -= entry->preedit_length;
+      else
+       {
+         index = cursor_index;
+         trailing = 0;
+       }
+    }
 
   pos = g_utf8_pointer_to_offset (entry->text, entry->text + index);
   
@@ -1356,15 +1862,14 @@ gtk_entry_get_cursor_locations (GtkEntry *entry,
                                gint     *strong_x,
                                gint     *weak_x)
 {
-  GtkEditable *editable = GTK_EDITABLE (entry);
-  int index;
+  PangoLayout *layout = gtk_entry_get_layout (entry, TRUE);
+  gint index = g_utf8_offset_to_pointer (entry->text, entry->current_pos) - entry->text;
 
   PangoRectangle strong_pos, weak_pos;
 
-  gtk_entry_ensure_layout (entry);
-  
-  index = g_utf8_offset_to_pointer (entry->text, editable->current_pos) - entry->text;
-  pango_layout_get_cursor_pos (entry->layout, index, &strong_pos, &weak_pos);
+  index += entry->preedit_cursor;
+  pango_layout_get_cursor_pos (layout, index, &strong_pos, &weak_pos);
+  g_object_unref (G_OBJECT (layout));
 
   if (strong_x)
     *strong_x = strong_pos.x / PANGO_SCALE;
@@ -1374,13 +1879,14 @@ gtk_entry_get_cursor_locations (GtkEntry *entry,
 }
 
 static void
-entry_adjust_scroll (GtkEntry *entry)
+gtk_entry_adjust_scroll (GtkEntry *entry)
 {
   GtkWidget *widget;
   gint min_offset, max_offset;
   gint text_area_width;
   gint strong_x, weak_x;
   gint strong_xoffset, weak_xoffset;
+  PangoLayout *layout;
   PangoLayoutLine *line;
   PangoRectangle logical_rect;
 
@@ -1389,17 +1895,19 @@ entry_adjust_scroll (GtkEntry *entry)
 
   widget = GTK_WIDGET (entry);
 
-  if (!entry->layout || !GTK_WIDGET_REALIZED (entry))
+  if (!GTK_WIDGET_REALIZED (entry))
     return;
   
   gdk_window_get_size (entry->text_area, &text_area_width, NULL);
   text_area_width -= 2 * INNER_BORDER;
 
-  line = pango_layout_get_lines (entry->layout)->data;
-  
-  /* Display as much text as we can */
+  layout = gtk_entry_get_layout (entry, TRUE);
+  line = pango_layout_get_lines (layout)->data;
 
   pango_layout_line_get_extents (line, NULL, &logical_rect);
+  g_object_unref (G_OBJECT (layout));
+
+  /* Display as much text as we can */
 
   if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
     {
@@ -1410,248 +1918,61 @@ entry_adjust_scroll (GtkEntry *entry)
     {
       max_offset = logical_rect.width / PANGO_SCALE - text_area_width;
       min_offset = MIN (0, max_offset);
-    }
-
-  entry->scroll_offset = CLAMP (entry->scroll_offset, min_offset, max_offset);
-
-  /* And make sure cursors are on screen. Note that the cursor is
-   * actually drawn one pixel into the INNER_BORDER space on
-   * the right, when the scroll is at the utmost right. This
-   * looks better to to me than confining the cursor inside the
-   * border entirely, though it means that the cursor gets one
-   * pixel closer to the the edge of the widget on the right than
-   * on the left. This might need changing if one changed
-   * INNER_BORDER from 2 to 1, as one would do on a
-   * small-screen-real-estate display.
-   *
-   * We always make sure that the strong cursor is on screen, and
-   * put the weak cursor on screen if possible.
-   */
-
-  gtk_entry_get_cursor_locations (entry, &strong_x, &weak_x);
-  
-  strong_xoffset = strong_x - entry->scroll_offset;
-
-  if (strong_xoffset < 0)
-    {
-      entry->scroll_offset += strong_xoffset;
-      strong_xoffset = 0;
-    }
-  else if (strong_xoffset > text_area_width)
-    {
-      entry->scroll_offset += strong_xoffset - text_area_width;
-      strong_xoffset = text_area_width;
-    }
-
-  weak_xoffset = weak_x - entry->scroll_offset;
-
-  if (weak_xoffset < 0 && strong_xoffset - weak_xoffset <= text_area_width)
-    {
-      entry->scroll_offset += weak_xoffset;
-    }
-  else if (weak_xoffset > text_area_width &&
-          strong_xoffset - (weak_xoffset - text_area_width) >= 0)
-    {
-      entry->scroll_offset += weak_xoffset - text_area_width;
-    }
-
-  gtk_widget_queue_draw (GTK_WIDGET (entry));
-}
-
-static void
-gtk_entry_insert_text (GtkEditable *editable,
-                      const gchar *new_text,
-                      gint         new_text_length,
-                      gint        *position)
-{
-  gint index;
-  gint n_chars;
-  GtkEntry *entry;
-  GtkWidget *widget;
-  
-  g_return_if_fail (editable != NULL);
-  g_return_if_fail (GTK_IS_ENTRY (editable));
-  g_return_if_fail (position != NULL);
-  g_return_if_fail (*position >= 0 || *position < GTK_ENTRY (editable)->text_size);
-
-  entry = GTK_ENTRY (editable);
-  widget = GTK_WIDGET (editable);
-
-  if (new_text_length < 0)
-    new_text_length = strlen (new_text);
-
-  n_chars = g_utf8_strlen (new_text, new_text_length);
-  if (entry->text_max_length > 0 && n_chars + entry->text_length > entry->text_max_length)
-    {
-      gdk_beep ();
-      n_chars = entry->text_max_length - entry->text_length;
-    }
-
-  if (new_text_length + entry->n_bytes + 1 > entry->text_size)
-    {
-      while (new_text_length + entry->n_bytes + 1 > entry->text_size)
-       {
-         if (entry->text_size == 0)
-           entry->text_size = MIN_SIZE;
-         else
-           {
-             if (2 * (guint)entry->text_size < MAX_SIZE &&
-                 2 * (guint)entry->text_size > entry->text_size)
-               entry->text_size *= 2;
-             else
-               {
-                 entry->text_size = MAX_SIZE;
-                 new_text_length = entry->text_size - new_text_length - 1;
-                 break;
-               }
-           }
-       }
-
-      entry->text = g_realloc (entry->text, entry->text_size);
-    }
-
-  index = g_utf8_offset_to_pointer (entry->text, *position) - entry->text;
-
-  g_memmove (entry->text + index + new_text_length, entry->text + index, entry->n_bytes - index);
-  memcpy (entry->text + index, new_text, new_text_length);
-
-  entry->n_bytes += new_text_length;
-  entry->text_length += n_chars;
-
-  /* NUL terminate for safety and convenience */
-  entry->text[entry->n_bytes] = '\0';
-  
-  if (editable->current_pos > *position)
-    editable->current_pos += n_chars;
-  
-  if (editable->selection_start_pos > *position)
-    editable->selection_start_pos += n_chars;
-
-  if (editable->selection_end_pos > *position)
-    editable->selection_end_pos += n_chars;
-
-  *position += n_chars;
-
-  if (entry->layout)
-    pango_layout_set_text (entry->layout, entry->text, entry->n_bytes);
-
-  gtk_entry_queue_draw (entry);
-}
-
-static void
-gtk_entry_delete_text (GtkEditable *editable,
-                      gint         start_pos,
-                      gint         end_pos)
-{
-  GtkEntry *entry;
-  
-  g_return_if_fail (editable != NULL);
-  g_return_if_fail (GTK_IS_ENTRY (editable));
-
-  entry = GTK_ENTRY (editable);
-
-  if (end_pos < 0)
-    end_pos = entry->text_length;
-  
-  if ((start_pos < end_pos) &&
-      (start_pos >= 0) &&
-      (end_pos <= entry->text_length))
-    {
-      gint start_index = g_utf8_offset_to_pointer (entry->text, start_pos) - entry->text;
-      gint end_index = g_utf8_offset_to_pointer (entry->text, end_pos) - entry->text;
-
-      g_memmove (entry->text + start_index, entry->text + end_index, entry->n_bytes - end_index);
-      entry->text_length -= (end_pos - start_pos);
-      entry->n_bytes -= (end_index - start_index);
-      
-      if (editable->current_pos > start_pos)
-       editable->current_pos -= MIN (editable->current_pos, end_pos) - start_pos;
-
-      if (editable->selection_start_pos > start_pos)
-       editable->selection_start_pos -= MIN (editable->selection_start_pos, end_pos) - start_pos;
-
-      if (editable->selection_end_pos > start_pos)
-       editable->selection_end_pos -= MIN (editable->selection_end_pos, end_pos) - start_pos;
-
-    }
-
-  gtk_entry_queue_draw (entry);
-
-  if (entry->layout)
-    pango_layout_set_text (entry->layout, entry->text, entry->n_bytes);
-}
-
-static void
-gtk_entry_update_text (GtkEditable *editable,
-                      gint         start_pos,
-                      gint         end_pos)
-{
-  GtkEntry *entry = GTK_ENTRY (editable);
-  
-  gtk_entry_queue_draw (entry);
-}
-
-static gchar *    
-gtk_entry_get_chars      (GtkEditable   *editable,
-                         gint           start_pos,
-                         gint           end_pos)
-{
-  GtkEntry *entry;
-  gint start_index, end_index;
-  
-  g_return_val_if_fail (editable != NULL, NULL);
-  g_return_val_if_fail (GTK_IS_ENTRY (editable), NULL);
-
-  entry = GTK_ENTRY (editable);
-
-  if (end_pos < 0)
-    end_pos = entry->text_length;
-
-  start_pos = MIN (entry->text_length, start_pos);
-  end_pos = MIN (entry->text_length, end_pos);
-
-  start_index = g_utf8_offset_to_pointer (entry->text, start_pos) - entry->text;
-  end_index = g_utf8_offset_to_pointer (entry->text, end_pos) - entry->text;
-
-  return g_strndup (entry->text + start_index, end_index - start_index);
-}
+    }
 
-static void 
-gtk_entry_move_cursor (GtkEditable *editable,
-                      gint         x,
-                      gint         y)
-{
-  GtkEntry *entry;
-  gint index;
+  entry->scroll_offset = CLAMP (entry->scroll_offset, min_offset, max_offset);
 
-  entry = GTK_ENTRY (editable);
+  /* And make sure cursors are on screen. Note that the cursor is
+   * actually drawn one pixel into the INNER_BORDER space on
+   * the right, when the scroll is at the utmost right. This
+   * looks better to to me than confining the cursor inside the
+   * border entirely, though it means that the cursor gets one
+   * pixel closer to the the edge of the widget on the right than
+   * on the left. This might need changing if one changed
+   * INNER_BORDER from 2 to 1, as one would do on a
+   * small-screen-real-estate display.
+   *
+   * We always make sure that the strong cursor is on screen, and
+   * put the weak cursor on screen if possible.
+   */
 
-  index = g_utf8_offset_to_pointer (entry->text, editable->current_pos) - entry->text;
+  gtk_entry_get_cursor_locations (entry, &strong_x, &weak_x);
   
-  /* Horizontal motion */
+  strong_xoffset = strong_x - entry->scroll_offset;
 
-  if ((gint)editable->current_pos < -x)
-    editable->current_pos = 0;
-  else if (editable->current_pos + x > entry->text_length)
-    editable->current_pos = entry->text_length;
-  else
-    editable->current_pos += x;
+  if (strong_xoffset < 0)
+    {
+      entry->scroll_offset += strong_xoffset;
+      strong_xoffset = 0;
+    }
+  else if (strong_xoffset > text_area_width)
+    {
+      entry->scroll_offset += strong_xoffset - text_area_width;
+      strong_xoffset = text_area_width;
+    }
+
+  weak_xoffset = weak_x - entry->scroll_offset;
 
-  /* Ignore vertical motion */
+  if (weak_xoffset < 0 && strong_xoffset - weak_xoffset <= text_area_width)
+    {
+      entry->scroll_offset += weak_xoffset;
+    }
+  else if (weak_xoffset > text_area_width &&
+          strong_xoffset - (weak_xoffset - text_area_width) >= 0)
+    {
+      entry->scroll_offset += weak_xoffset - text_area_width;
+    }
 }
 
-static void 
-gtk_entry_move_cursor_visually (GtkEditable *editable,
-                               gint         count)
+static gint
+gtk_entry_move_visually (GtkEntry *entry,
+                        gint      start,
+                        gint      count)
 {
-  GtkEntry *entry;
   gint index;
+  PangoLayout *layout = gtk_entry_get_layout (entry, FALSE);
 
-  entry = GTK_ENTRY (editable);
-
-  index = g_utf8_offset_to_pointer (entry->text, editable->current_pos) - entry->text;
-  
-  gtk_entry_ensure_layout (entry);
+  index = g_utf8_offset_to_pointer (entry->text, start) - entry->text;
 
   while (count != 0)
     {
@@ -1659,12 +1980,12 @@ gtk_entry_move_cursor_visually (GtkEditable *editable,
       
       if (count > 0)
        {
-         pango_layout_move_cursor_visually (entry->layout, index, 0, 1, &new_index, &new_trailing);
+         pango_layout_move_cursor_visually (layout, index, 0, 1, &new_index, &new_trailing);
          count--;
        }
       else
        {
-         pango_layout_move_cursor_visually (entry->layout, index, 0, -1, &new_index, &new_trailing);
+         pango_layout_move_cursor_visually (layout, index, 0, -1, &new_index, &new_trailing);
          count++;
        }
 
@@ -1677,289 +1998,341 @@ gtk_entry_move_cursor_visually (GtkEditable *editable,
        index = new_index;
     }
 
-  editable->current_pos = g_utf8_pointer_to_offset (entry->text, entry->text + index);
-}
-
-static void
-gtk_move_forward_character (GtkEntry *entry)
-{
-  gtk_entry_move_cursor_visually (GTK_EDITABLE (entry), 1);
-}
-
-static void
-gtk_move_backward_character (GtkEntry *entry)
-{
-  gtk_entry_move_cursor_visually (GTK_EDITABLE (entry), -1);
-}
-
-static void 
-gtk_entry_move_word (GtkEditable *editable,
-                    gint         n)
-{
-  while (n-- > 0)
-    gtk_move_forward_word (GTK_ENTRY (editable));
-  while (n++ < 0)
-    gtk_move_backward_word (GTK_ENTRY (editable));
+  g_object_unref (G_OBJECT (layout));
+  
+  return g_utf8_pointer_to_offset (entry->text, entry->text + index);
 }
 
-static void
-gtk_move_forward_word (GtkEntry *entry)
+static gint
+gtk_entry_move_forward_word (GtkEntry *entry,
+                            gint      start)
 {
-  GtkEditable *editable;
-  gint i;
-
-  editable = GTK_EDITABLE (entry);
+  gint new_pos = start;
 
   /* Prevent any leak of information */
-  if (!editable->visible)
+  if (!entry->visible)
     {
-      editable->current_pos = entry->text_length;
-      return;
+      new_pos = entry->text_length;
     }
-
-  if (entry->text && (editable->current_pos < entry->text_length))
+  else if (entry->text && (new_pos < entry->text_length))
     {
+      PangoLayout *layout = gtk_entry_get_layout (entry, FALSE);
       PangoLogAttr *log_attrs;
-      gint n_attrs, old_pos;
-
-      gtk_entry_ensure_layout (entry);
-      pango_layout_get_log_attrs (entry->layout, &log_attrs, &n_attrs);
+      gint n_attrs;
 
-      i = old_pos = editable->current_pos;
+      pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs);
 
       /* Advance over white space */
-      while (i < n_attrs && log_attrs[i].is_white)
-       i++;
+      while (new_pos < n_attrs && log_attrs[new_pos].is_white)
+       new_pos++;
       
       /* Find the next word beginning */
-      i++;
-      while (i < n_attrs && !log_attrs[i].is_word_stop)
-       i++;
-
-      editable->current_pos = MAX (entry->text_length, i);
+      new_pos++;
+      while (new_pos < n_attrs && !log_attrs[new_pos].is_word_stop)
+       new_pos++;
 
       /* Back up over white space */
-      while (i > 0 && log_attrs[i - 1].is_white)
-       i--;
-
-      if (i != old_pos)
-       editable->current_pos = i;
+      while (new_pos > 0 && log_attrs[new_pos - 1].is_white)
+       new_pos--;
 
       g_free (log_attrs);
+      g_object_unref (G_OBJECT (layout));
     }
+
+  return new_pos;
 }
 
-static void
-gtk_move_backward_word (GtkEntry *entry)
-{
-  GtkEditable *editable;
-  gint i;
 
-  editable = GTK_EDITABLE (entry);
+static gint
+gtk_entry_move_backward_word (GtkEntry *entry,
+                             gint      start)
+{
+  gint new_pos = start;
 
   /* Prevent any leak of information */
-  if (!editable->visible)
+  if (!entry->visible)
     {
-      editable->current_pos = 0;
-      return;
+      new_pos = 0;
     }
-
-  if (entry->text && editable->current_pos > 0)
+  else if (entry->text && start > 0)
     {
+      PangoLayout *layout = gtk_entry_get_layout (entry, FALSE);
       PangoLogAttr *log_attrs;
       gint n_attrs;
 
-      gtk_entry_ensure_layout (entry);
-      pango_layout_get_log_attrs (entry->layout, &log_attrs, &n_attrs);
+      pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs);
 
-      i = editable->current_pos - 1;
+      new_pos = start - 1;
 
       /* Find the previous word beginning */
-      while (i > 0 && !log_attrs[i].is_word_stop)
-       i--;
+      while (new_pos > 0 && !log_attrs[new_pos].is_word_stop)
+       new_pos--;
 
       g_free (log_attrs);
+      g_object_unref (G_OBJECT (layout));
     }
+
+  return new_pos;
 }
 
 static void
-gtk_entry_move_to_column (GtkEditable *editable, gint column)
+gtk_entry_delete_whitespace (GtkEntry *entry)
 {
-  GtkEntry *entry;
+  PangoLayout *layout = gtk_entry_get_layout (entry, FALSE);
+  PangoLogAttr *log_attrs;
+  gint n_attrs;
+  gint start, end;
 
-  entry = GTK_ENTRY (editable);
+  pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs);
+
+  start = end = entry->current_pos;
   
-  if (column < 0 || column > entry->text_length)
-    editable->current_pos = entry->text_length;
-  else
-    editable->current_pos = column;
+  while (start > 0 && log_attrs[start-1].is_white)
+    start--;
+
+  while (end < n_attrs && log_attrs[start-1].is_white)
+    end++;
+
+  g_free (log_attrs);
+  g_object_unref (G_OBJECT (layout));
+
+  if (start != end)
+    gtk_editable_delete_text (GTK_EDITABLE (entry), start, end);
 }
 
+
 static void
-gtk_move_beginning_of_line (GtkEntry *entry)
+gtk_entry_select_word (GtkEntry *entry)
 {
-  gtk_entry_move_to_column (GTK_EDITABLE (entry), 0);
+  gint start_pos = gtk_entry_move_backward_word (entry, entry->current_pos);
+  gint end_pos = gtk_entry_move_forward_word (entry, entry->current_pos);
+
+  gtk_editable_select_region (GTK_EDITABLE (entry), start_pos, end_pos);
 }
 
 static void
-gtk_move_end_of_line (GtkEntry *entry)
+gtk_entry_select_line (GtkEntry *entry)
 {
-  gtk_entry_move_to_column (GTK_EDITABLE (entry), -1);
+  gtk_editable_select_region (GTK_EDITABLE (entry), 0, -1);
 }
 
-static void
-gtk_entry_kill_char (GtkEditable *editable,
-                    gint         direction)
+/*
+ * Like gtk_editable_get_chars, but if the editable is not
+ * visible, return asterisks; also convert result to UTF-8.
+ */
+static char *    
+gtk_entry_get_public_chars (GtkEntry *entry,
+                           gint      start,
+                           gint      end)
 {
-  if (editable->selection_start_pos != editable->selection_end_pos)
-    gtk_editable_delete_selection (editable);
+  if (end < 0)
+    end = entry->text_length;
+  
+  if (entry->visible)
+    return gtk_editable_get_chars (GTK_EDITABLE (entry), start, end);
   else
     {
-      gint old_pos = editable->current_pos;
-      if (direction >= 0)
-       {
-         gtk_entry_move_cursor (editable, 1, 0);
-         gtk_editable_delete_text (editable, old_pos, editable->current_pos);
-       }
-      else
-       {
-         gtk_entry_move_cursor (editable, -1, 0);
-         gtk_editable_delete_text (editable, editable->current_pos, old_pos);
-       }
+      gchar *str;
+      gint i;
+      gint n_chars = end - start;
+       
+      str = g_malloc (n_chars + 1);
+      for (i = 0; i < n_chars; i++)
+       str[i] = '*';
+      str[i] = '\0';
+      
+      return str;
     }
+
 }
 
 static void
-gtk_delete_forward_character (GtkEntry *entry)
+paste_received (GtkClipboard *clipboard,
+               const gchar  *text,
+               gpointer      data)
 {
-  gtk_entry_kill_char (GTK_EDITABLE (entry), 1);
+  GtkEntry *entry = GTK_ENTRY (data);
+  GtkEditable *editable = GTK_EDITABLE (entry);
+      
+  if (text)
+    {
+      gint pos = entry->current_pos;
+      
+      gtk_editable_insert_text (editable, text, -1, &pos);
+      gtk_editable_set_position (editable, pos);
+    }
+
+  g_object_unref (G_OBJECT (entry));
 }
 
 static void
-gtk_delete_backward_character (GtkEntry *entry)
+gtk_entry_paste (GtkEntry *entry,
+                GdkAtom   selection)
 {
-  gtk_entry_kill_char (GTK_EDITABLE (entry), -1);
+  g_object_ref (G_OBJECT (entry));
+  gtk_clipboard_request_text (gtk_clipboard_get (selection),
+                             paste_received, entry);
 }
 
 static void
-gtk_entry_kill_word (GtkEditable *editable,
-                    gint         direction)
+primary_get_cb (GtkClipboard     *clipboard,
+               GtkSelectionData *selection_data,
+               guint             info,
+               gpointer          data)
 {
-  if (editable->selection_start_pos != editable->selection_end_pos)
-    gtk_editable_delete_selection (editable);
-  else
+  GtkEntry *entry = GTK_ENTRY (data);
+  gint start, end;
+  
+  if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start, &end))
     {
-      gint old_pos = editable->current_pos;
-      if (direction >= 0)
-       {
-         gtk_entry_move_word (editable, 1);
-         gtk_editable_delete_text (editable, old_pos, editable->current_pos);
-       }
-      else
-       {
-         gtk_entry_move_word (editable, -1);
-         gtk_editable_delete_text (editable, editable->current_pos, old_pos);
-       }
+      gchar *str = gtk_entry_get_public_chars (entry, start, end);
+      gtk_selection_data_set_text (selection_data, str);
+      g_free (str);
     }
 }
 
 static void
-gtk_delete_forward_word (GtkEntry *entry)
+primary_clear_cb (GtkClipboard *clipboard,
+                 gpointer      data)
 {
-  gtk_entry_kill_word (GTK_EDITABLE (entry), 1);
-}
+  GtkEntry *entry = GTK_ENTRY (data);
 
-static void
-gtk_delete_backward_word (GtkEntry *entry)
-{
-  gtk_entry_kill_word (GTK_EDITABLE (entry), -1);
+  gtk_editable_select_region (GTK_EDITABLE (entry), entry->current_pos, entry->current_pos);
 }
 
 static void
-gtk_entry_kill_line (GtkEditable *editable,
-                    gint         direction)
-{
-  gint old_pos = editable->current_pos;
-  if (direction >= 0)
+gtk_entry_update_primary_selection (GtkEntry *entry)
+{
+  static const GtkTargetEntry targets[] = {
+    { "UTF8_STRING", 0, 0 },
+    { "STRING", 0, 0 },
+    { "TEXT",   0, 0 }, 
+    { "COMPOUND_TEXT", 0, 0 }
+  };
+  
+  GtkClipboard *clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);
+  gint start, end;
+  
+  if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start, &end))
     {
-      gtk_entry_move_to_column (editable, -1);
-      gtk_editable_delete_text (editable, old_pos, editable->current_pos);
+      if (!gtk_clipboard_set_with_owner (clipboard, targets, G_N_ELEMENTS (targets),
+                                        primary_get_cb, primary_clear_cb, G_OBJECT (entry)))
+       primary_clear_cb (clipboard, entry);
     }
   else
     {
-      gtk_entry_move_to_column (editable, 0);
-      gtk_editable_delete_text (editable, editable->current_pos, old_pos);
+      if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (entry))
+       gtk_clipboard_clear (clipboard);
     }
 }
 
-static void
-gtk_delete_line (GtkEntry *entry)
+/* Public API
+ */
+
+GtkWidget*
+gtk_entry_new (void)
 {
-  gtk_entry_move_to_column (GTK_EDITABLE (entry), 0);
-  gtk_entry_kill_line (GTK_EDITABLE (entry), 1);
+  return GTK_WIDGET (gtk_type_new (GTK_TYPE_ENTRY));
 }
 
-static void
-gtk_delete_to_line_end (GtkEntry *entry)
+GtkWidget*
+gtk_entry_new_with_max_length (guint16 max)
 {
-  gtk_editable_delete_text (GTK_EDITABLE(entry), GTK_EDITABLE(entry)->current_pos, entry->text_length);
+  GtkEntry *entry;
+
+  entry = gtk_type_new (GTK_TYPE_ENTRY);
+  entry->text_max_length = max;
+
+  return GTK_WIDGET (entry);
 }
 
-static void
-gtk_select_word (GtkEntry *entry,
-                guint32   time)
+void
+gtk_entry_set_text (GtkEntry *entry,
+                   const gchar *text)
 {
+  gint tmp_pos;
+
   GtkEditable *editable;
-  gint start_pos;
-  gint end_pos;
+
+  g_return_if_fail (entry != NULL);
+  g_return_if_fail (GTK_IS_ENTRY (entry));
+  g_return_if_fail (text != NULL);
 
   editable = GTK_EDITABLE (entry);
+  
+  gtk_editable_delete_text (GTK_EDITABLE(entry), 0, -1);
+
+  tmp_pos = 0;
+  gtk_editable_insert_text (editable, text, strlen (text), &tmp_pos);
+}
 
-  gtk_move_backward_word (entry);
-  start_pos = editable->current_pos;
+void
+gtk_entry_append_text (GtkEntry *entry,
+                      const gchar *text)
+{
+  gint tmp_pos;
 
-  gtk_move_forward_word (entry);
-  end_pos = editable->current_pos;
+  g_return_if_fail (entry != NULL);
+  g_return_if_fail (GTK_IS_ENTRY (entry));
+  g_return_if_fail (text != NULL);
 
-  editable->has_selection = TRUE;
-  gtk_entry_set_selection (editable, start_pos, end_pos);
-  gtk_editable_claim_selection (editable, start_pos != end_pos, time);
+  tmp_pos = entry->text_length;
+  gtk_editable_insert_text (GTK_EDITABLE(entry), text, -1, &tmp_pos);
 }
 
-static void
-gtk_select_line (GtkEntry *entry,
-                guint32   time)
+void
+gtk_entry_prepend_text (GtkEntry *entry,
+                       const gchar *text)
 {
-  GtkEditable *editable;
+  gint tmp_pos;
 
-  editable = GTK_EDITABLE (entry);
+  g_return_if_fail (entry != NULL);
+  g_return_if_fail (GTK_IS_ENTRY (entry));
+  g_return_if_fail (text != NULL);
+
+  tmp_pos = 0;
+  gtk_editable_insert_text (GTK_EDITABLE(entry), text, -1, &tmp_pos);
+}
 
-  editable->has_selection = TRUE;
-  gtk_entry_set_selection (editable, 0, entry->text_length);
-  gtk_editable_claim_selection (editable, entry->text_length != 0, time);
+void
+gtk_entry_set_position (GtkEntry *entry,
+                       gint       position)
+{
+  g_return_if_fail (entry != NULL);
+  g_return_if_fail (GTK_IS_ENTRY (entry));
 
-  editable->current_pos = editable->selection_end_pos;
+  gtk_editable_set_position (GTK_EDITABLE (entry), position);
 }
 
-static void 
-gtk_entry_set_selection (GtkEditable       *editable,
-                        gint               start,
-                        gint               end)
+void
+gtk_entry_set_visibility (GtkEntry *entry,
+                         gboolean visible)
 {
-  GtkEntry *entry;
-  
-  g_return_if_fail (editable != NULL);
-  g_return_if_fail (GTK_IS_ENTRY (editable));
+  g_return_if_fail (entry != NULL);
+  g_return_if_fail (GTK_IS_ENTRY (entry));
 
-  entry = GTK_ENTRY (editable);
+  entry->visible = visible ? TRUE : FALSE;
 
-  if (end < 0)
-    end = GTK_ENTRY (editable)->text_length;
-  
-  editable->selection_start_pos = start;
-  editable->selection_end_pos = end;
+  gtk_entry_recompute (entry);
+}
+
+void
+gtk_entry_set_editable(GtkEntry *entry,
+                      gboolean  editable)
+{
+  g_return_if_fail (entry != NULL);
+  g_return_if_fail (GTK_IS_ENTRY (entry));
+
+  gtk_editable_set_editable (GTK_EDITABLE (entry), editable);
+}
+
+gchar*
+gtk_entry_get_text (GtkEntry *entry)
+{
+  g_return_val_if_fail (entry != NULL, NULL);
+  g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
 
-  gtk_entry_queue_draw (GTK_ENTRY (editable));
+  return entry->text;
 }
 
 void       
@@ -1983,63 +2356,66 @@ gtk_entry_set_max_length (GtkEntry     *entry,
   entry->text_max_length = max;
 }
 
-                         
-static void 
-gtk_entry_style_set    (GtkWidget      *widget,
-                        GtkStyle       *previous_style)
+/* Quick hack of a popup menu
+ */
+static void
+activate_cb (GtkWidget *menuitem,
+            GtkEntry  *entry)
 {
-  GtkEntry *entry = GTK_ENTRY (widget);
-
-  if (previous_style && GTK_WIDGET_REALIZED (widget))
-    {
-      entry_adjust_scroll (entry);
-
-      gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
-      gdk_window_set_background (entry->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]);
-    }
-
-  if (entry->layout)
-    pango_layout_context_changed (entry->layout);
+  const gchar *signal = gtk_object_get_data (GTK_OBJECT (menuitem), "gtk-signal");
+  gtk_signal_emit_by_name (GTK_OBJECT (entry), signal);
 }
 
-static void 
-gtk_entry_direction_changed (GtkWidget        *widget,
-                            GtkTextDirection  previous_dir)
+static void
+append_action_signal (GtkEntry     *entry,
+                     GtkWidget    *menu,
+                     const gchar  *label,
+                     const gchar  *signal)
 {
-  GtkEntry *entry = GTK_ENTRY (widget);
+  GtkWidget *menuitem = gtk_menu_item_new_with_label (label);
 
-  if (entry->layout)
-    pango_layout_context_changed (entry->layout);
+  gtk_object_set_data (GTK_OBJECT (menuitem), "gtk-signal", (char *)signal);
+  gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
+                     activate_cb, entry);
 
-  GTK_WIDGET_CLASS (parent_class)->direction_changed (widget, previous_dir);
+  gtk_widget_show (menuitem);
+  gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
 }
-
+       
 static void
-gtk_entry_state_changed (GtkWidget      *widget,
-                        GtkStateType    previous_state)
+popup_menu_detach (GtkWidget *attach_widget,
+                  GtkMenu   *menu)
 {
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (GTK_IS_ENTRY (widget));
-
-  if (GTK_WIDGET_REALIZED (widget))
-    {
-      gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
-      gdk_window_set_background (GTK_ENTRY (widget)->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]);
-    }
-
-  if (GTK_WIDGET_DRAWABLE (widget))
-    gtk_widget_queue_clear(widget);
+  GTK_ENTRY (attach_widget)->popup_menu = NULL;
 }
 
 static void
-gtk_entry_commit_cb (GtkIMContext *context,
-                    const gchar  *str,
-                    GtkEntry     *entry)
+gtk_entry_popup_menu (GtkEntry       *entry,
+                     GdkEventButton *event)
 {
-  GtkEditable *editable = GTK_EDITABLE (entry);
-  gint tmp_pos = editable->current_pos;
+  if (!entry->popup_menu)
+    {
+      GtkWidget *menuitem;
+      
+      entry->popup_menu = gtk_menu_new ();
 
-  gtk_editable_insert_text (editable, str, strlen (str), &tmp_pos);
-  editable->current_pos = tmp_pos;
-}
+      gtk_menu_attach_to_widget (GTK_MENU (entry->popup_menu),
+                                GTK_WIDGET (entry),
+                                popup_menu_detach);
+
+      append_action_signal (entry, entry->popup_menu, _("Cut"), "cut_clipboard");
+      append_action_signal (entry, entry->popup_menu, _("Copy"), "copy_clipboard");
+      append_action_signal (entry, entry->popup_menu, _("Paste"), "paste_clipboard");
 
+      menuitem = gtk_menu_item_new (); /* Separator */
+      gtk_widget_show (menuitem);
+      gtk_menu_shell_append (GTK_MENU_SHELL (entry->popup_menu), menuitem);
+
+      gtk_im_multicontext_append_menuitems (GTK_IM_MULTICONTEXT (entry->im_context),
+                                           GTK_MENU_SHELL (entry->popup_menu));
+    }
+
+  gtk_menu_popup (GTK_MENU (entry->popup_menu), NULL, NULL,
+                 NULL, NULL,
+                 event->button, event->time);
+}
index 9f7f38899e405a62b8df1de81493c1f2cb554f29..765da78f033c693f612c2fb60b3ba8738bca981c 100644 (file)
@@ -51,57 +51,106 @@ typedef struct _GtkEntryClass  GtkEntryClass;
 
 struct _GtkEntry
 {
-  GtkEditable editable;
+  GtkWidget  widget;
 
-  GdkWindow *text_area;
-  GdkPixmap *backing_pixmap;
-  GdkCursor *cursor;
   gchar     *text;
 
-  guint16 text_size;   /* allocated size, in bytes */
+  guint      editable : 1;
+  guint      visible  : 1;
+  guint      overwrite_mode : 1;
 
   guint16 text_length; /* length in use, in chars */
   guint16 text_max_length;
 
   /*< private >*/
+  GdkWindow *text_area;
+  GtkIMContext *im_context;
+  GtkWidget   *popup_menu;
+  
+  gint         current_pos;
+  gint         selection_bound;
+  
+  PangoLayout *cached_layout;
+  guint        cache_includes_preedit : 1;
+
+  guint        need_im_reset : 1;
+
   guint   button;
-  guint32 timer;
-  guint16 n_bytes;     /* length in use, in bytes */
-  PangoLayout *layout;
+  guint   timer;
+  guint   recompute_idle;
   gint    scroll_offset;
   gint    ascent;      /* font ascent, in pango units  */
   gint    descent;     /* font descent, in pango units  */
-  GtkIMContext *im_context;
+  
+  guint16 text_size;   /* allocated size, in bytes */
+  guint16 n_bytes;     /* length in use, in bytes */
+
+  guint16 preedit_length;      /* length of preedit string, in bytes */
+  guint16 preedit_cursor;      /* offset of cursor within preedit string, in bytes */
 };
 
 struct _GtkEntryClass
 {
-  GtkEditableClass parent_class;
+  GtkWidgetClass parent_class;
+  
+  /* Notification of changes
+   */
+  void (* changed)          (GtkEntry       *entry);
+  void (* insert_text)      (GtkEntry       *entry,
+                            const gchar    *text,
+                            gint            length,
+                            gint           *position);
+  void (* delete_text)      (GtkEntry       *entry,
+                            gint            start_pos,
+                            gint            end_pos);
+
+  /* Action signals
+   */
+  void (* activate)         (GtkEntry       *entry);
+  void (* move)             (GtkEntry       *entry,
+                            GtkMovementStep step,
+                            gint            count,
+                            gboolean        extend_selection);
+  void (* insert)           (GtkEntry       *entry,
+                            const gchar    *str);
+  void (* delete)           (GtkEntry       *entry,
+                            GtkDeleteType   type,
+                            gint            count);
+  void (* cut_clipboard)    (GtkEntry       *entry);
+  void (* copy_clipboard)   (GtkEntry       *entry);
+  void (* paste_clipboard)  (GtkEntry       *entry);
+  void (* toggle_overwrite) (GtkEntry       *entry);
 };
 
 GtkType    gtk_entry_get_type                  (void) G_GNUC_CONST;
 GtkWidget* gtk_entry_new                       (void);
-GtkWidget* gtk_entry_new_with_max_length       (guint16       max);
+void       gtk_entry_set_visibility            (GtkEntry      *entry,
+                                                gboolean       visible);
+void       gtk_entry_set_editable              (GtkEntry      *entry,
+                                                gboolean       editable);
+/* text is truncated if needed */
+void       gtk_entry_set_max_length            (GtkEntry      *entry,
+                                                guint16        max);
+
+/* Somewhat more convenient than the GtkEditable generic functions
+ */
 void       gtk_entry_set_text                  (GtkEntry      *entry,
                                                 const gchar   *text);
+/* returns a reference to the text */
+gchar*     gtk_entry_get_text                  (GtkEntry      *entry);
+
+/* Deprecated compatibility functions
+ */
+GtkWidget* gtk_entry_new_with_max_length       (guint16       max);
 void       gtk_entry_append_text               (GtkEntry      *entry,
                                                 const gchar   *text);
 void       gtk_entry_prepend_text              (GtkEntry      *entry,
                                                 const gchar   *text);
 void       gtk_entry_set_position              (GtkEntry      *entry,
                                                 gint           position);
-/* returns a reference to the text */
-gchar*     gtk_entry_get_text                  (GtkEntry      *entry);
 void       gtk_entry_select_region             (GtkEntry      *entry,
                                                 gint           start,
                                                 gint           end);
-void       gtk_entry_set_visibility            (GtkEntry      *entry,
-                                                gboolean       visible);
-void       gtk_entry_set_editable              (GtkEntry      *entry,
-                                                gboolean       editable);
-/* text is truncated if needed */
-void       gtk_entry_set_max_length            (GtkEntry      *entry,
-                                                guint16        max);
 
 #ifdef __cplusplus
 }
index 753937f11fede28f956ab71d0878d2c02f618ada..3ced6d603649c48cf302f238459471bf9ef244b1 100644 (file)
@@ -35,7 +35,8 @@ static void gtk_im_context_init (GtkIMContext *im_context);
 
 static void     gtk_im_context_real_get_preedit_string (GtkIMContext       *context,
                                                        gchar             **str,
-                                                       PangoAttrList     **attrs);
+                                                       PangoAttrList     **attrs,
+                                                       gint               *cursor_pos);
 static gboolean gtk_im_context_real_filter_keypress    (GtkIMContext       *context,
                                                        GdkEventKey        *event);
 
@@ -118,12 +119,15 @@ gtk_im_context_init (GtkIMContext *im_context)
 static void
 gtk_im_context_real_get_preedit_string (GtkIMContext       *context,
                                        gchar             **str,
-                                       PangoAttrList     **attrs)
+                                       PangoAttrList     **attrs,
+                                       gint               *cursor_pos)
 {
   if (str)
     *str = g_strdup ("");
   if (attrs)
     *attrs = pango_attr_list_new ();
+  if (cursor_pos)
+    *cursor_pos = 0;
 }
 
 static gboolean
@@ -175,7 +179,8 @@ gtk_im_context_set_client_window (GtkIMContext *context,
 void
 gtk_im_context_get_preedit_string (GtkIMContext   *context,
                                   gchar         **str,
-                                  PangoAttrList **attrs)
+                                  PangoAttrList **attrs,
+                                  gint           *cursor_pos)
 {
   GtkIMContextClass *klass;
   
@@ -183,7 +188,7 @@ gtk_im_context_get_preedit_string (GtkIMContext   *context,
   g_return_if_fail (GTK_IS_IM_CONTEXT (context));
   
   klass = GTK_IM_CONTEXT_GET_CLASS (context);
-  klass->get_preedit_string (context, str, attrs);
+  klass->get_preedit_string (context, str, attrs, cursor_pos);
 }
 
 /**
@@ -235,7 +240,7 @@ gtk_im_context_focus_in (GtkIMContext   *context)
 }
 
 /**
- * gtk_im_context_focus_in:
+ * gtk_im_context_focus_out:
  * @context: a #GtkIMContext
  *
  * Notify the input method that the widget to which this
@@ -256,4 +261,25 @@ gtk_im_context_focus_out (GtkIMContext   *context)
     klass->focus_out (context);
 }
 
+/**
+ * gtk_im_context_reset:
+ * @context: a #GtkIMContext
+ *
+ * Notify the input method that a change such as a change in cursor
+ * position has been made. This will typically cause the input
+ * method to clear the preedit state.
+ **/
+void
+gtk_im_context_reset (GtkIMContext   *context)
+{
+  GtkIMContextClass *klass;
+  
+  g_return_if_fail (context != NULL);
+  g_return_if_fail (GTK_IS_IM_CONTEXT (context));
+
+  klass = GTK_IM_CONTEXT_GET_CLASS (context);
+  if (klass->reset)
+    klass->reset (context);
+}
+
 
index efc4ab64fe7b9b3d40b40e68b9894de89b540e14..6435c4eaf84748272331038f336e8f063fc57ff1 100644 (file)
@@ -60,11 +60,13 @@ struct _GtkIMContextClass
                                  GdkWindow      *window);
   void     (*get_preedit_string) (GtkIMContext   *context,
                                  gchar         **str,
-                                 PangoAttrList **attrs);
+                                 PangoAttrList **attrs,
+                                 gint           *cursor_pos);
   gboolean (*filter_keypress)    (GtkIMContext   *context,
                                  GdkEventKey    *event);
   void     (*focus_in)           (GtkIMContext   *context);
   void     (*focus_out)          (GtkIMContext   *context);
+  void     (*reset)              (GtkIMContext   *context);
 };
 
 GtkType       gtk_im_context_get_type           (void) G_GNUC_CONST;
@@ -72,12 +74,14 @@ GtkType       gtk_im_context_get_type           (void) G_GNUC_CONST;
 void          gtk_im_context_set_client_window  (GtkIMContext   *context,
                                                 GdkWindow      *window);
 void          gtk_im_context_get_preedit_string (GtkIMContext   *context,
-                                                char          **str,
-                                                PangoAttrList **attrs);
+                                                gchar         **str,
+                                                PangoAttrList **attrs,
+                                                gint           *cursor_pos);
 gboolean      gtk_im_context_filter_keypress    (GtkIMContext   *context,
                                                 GdkEventKey    *event);
 void          gtk_im_context_focus_in           (GtkIMContext   *context);
 void          gtk_im_context_focus_out          (GtkIMContext   *context);
+void          gtk_im_context_reset              (GtkIMContext   *context);
 
 #ifdef __cplusplus
 }
index edfdb57296b78770143ef8c785f0abe6cd5a7618..a01c85c3bd57a82b038bfb8fed512dd821303373 100644 (file)
 #include "gtksignal.h"
 #include "gtkimcontextsimple.h"
 
-typedef struct _GtkComposeSeq GtkComposeSeq;
+typedef struct _GtkComposeTable GtkComposeTable;
 
-struct _GtkComposeSeq
+struct _GtkComposeTable 
 {
-  guint16 keysyms[GTK_MAX_COMPOSE_LEN];
-  guint16 unicode;
+  guint16 *data;
+  gint max_seq_len;
+  gint n_seqs;
 };
 
 /* The following table was generated from the X compose tables include with
@@ -54,665 +55,671 @@ struct _GtkComposeSeq
  * that depend on the locale or selected input method. 
  */
 
-GtkComposeSeq gtk_compose_seqs[] = {
-  { { GDK_dead_grave,  GDK_space,      0,      0 },    0x0060 },       /* GRAVE_ACCENT */
-  { { GDK_dead_grave,  GDK_A,  0,      0 },    0x00C0 },       /* LATIN_CAPITAL_LETTER_A_WITH_GRAVE */
-  { { GDK_dead_grave,  GDK_E,  0,      0 },    0x00C8 },       /* LATIN_CAPITAL_LETTER_E_WITH_GRAVE */
-  { { GDK_dead_grave,  GDK_I,  0,      0 },    0x00CC },       /* LATIN_CAPITAL_LETTER_I_WITH_GRAVE */
-  { { GDK_dead_grave,  GDK_O,  0,      0 },    0x00D2 },       /* LATIN_CAPITAL_LETTER_O_WITH_GRAVE */
-  { { GDK_dead_grave,  GDK_U,  0,      0 },    0x00D9 },       /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */
-  { { GDK_dead_grave,  GDK_a,  0,      0 },    0x00E0 },       /* LATIN_SMALL_LETTER_A_WITH_GRAVE */
-  { { GDK_dead_grave,  GDK_e,  0,      0 },    0x00E8 },       /* LATIN_SMALL_LETTER_E_WITH_GRAVE */
-  { { GDK_dead_grave,  GDK_i,  0,      0 },    0x00EC },       /* LATIN_SMALL_LETTER_I_WITH_GRAVE */
-  { { GDK_dead_grave,  GDK_o,  0,      0 },    0x00F2 },       /* LATIN_SMALL_LETTER_O_WITH_GRAVE */
-  { { GDK_dead_grave,  GDK_u,  0,      0 },    0x00F9 },       /* LATIN_SMALL_LETTER_U_WITH_GRAVE */
-  { { GDK_dead_acute,  GDK_space,      0,      0 },    0x0027 },       /* APOSTROPHE */
-  { { GDK_dead_acute,  GDK_apostrophe, 0,      0 },    0x00B4 },       /* ACUTE_ACCENT */
-  { { GDK_dead_acute,  GDK_A,  0,      0 },    0x00C1 },       /* LATIN_CAPITAL_LETTER_A_WITH_ACUTE */
-  { { GDK_dead_acute,  GDK_E,  0,      0 },    0x00C9 },       /* LATIN_CAPITAL_LETTER_E_WITH_ACUTE */
-  { { GDK_dead_acute,  GDK_I,  0,      0 },    0x00CD },       /* LATIN_CAPITAL_LETTER_I_WITH_ACUTE */
-  { { GDK_dead_acute,  GDK_O,  0,      0 },    0x00D3 },       /* LATIN_CAPITAL_LETTER_O_WITH_ACUTE */
-  { { GDK_dead_acute,  GDK_U,  0,      0 },    0x00DA },       /* LATIN_CAPITAL_LETTER_U_WITH_ACUTE */
-  { { GDK_dead_acute,  GDK_Y,  0,      0 },    0x00DD },       /* LATIN_CAPITAL_LETTER_Y_WITH_ACUTE */
-  { { GDK_dead_acute,  GDK_a,  0,      0 },    0x00E1 },       /* LATIN_SMALL_LETTER_A_WITH_ACUTE */
-  { { GDK_dead_acute,  GDK_e,  0,      0 },    0x00E9 },       /* LATIN_SMALL_LETTER_E_WITH_ACUTE */
-  { { GDK_dead_acute,  GDK_i,  0,      0 },    0x00ED },       /* LATIN_SMALL_LETTER_I_WITH_ACUTE */
-  { { GDK_dead_acute,  GDK_o,  0,      0 },    0x00F3 },       /* LATIN_SMALL_LETTER_O_WITH_ACUTE */
-  { { GDK_dead_acute,  GDK_u,  0,      0 },    0x00FA },       /* LATIN_SMALL_LETTER_U_WITH_ACUTE */
-  { { GDK_dead_acute,  GDK_y,  0,      0 },    0x00FD },       /* LATIN_SMALL_LETTER_Y_WITH_ACUTE */
-  { { GDK_dead_acute,  GDK_acute,      0,      0 },    0x00B4 },       /* ACUTE_ACCENT */
-  { { GDK_dead_acute,  GDK_dead_acute, 0,      0 },    0x00B4 },       /* ACUTE_ACCENT */
-  { { GDK_dead_circumflex,     GDK_space,      0,      0 },    0x005E },       /* CIRCUMFLEX_ACCENT */
-  { { GDK_dead_circumflex,     GDK_minus,      0,      0 },    0x00AF },       /* MACRON */
-  { { GDK_dead_circumflex,     GDK_period,     0,      0 },    0x00B7 },       /* MIDDLE_DOT */
-  { { GDK_dead_circumflex,     GDK_slash,      0,      0 },    0x007C },       /* VERTICAL_LINE */
-  { { GDK_dead_circumflex,     GDK_0,  0,      0 },    0x00B0 },       /* DEGREE_SIGN */
-  { { GDK_dead_circumflex,     GDK_1,  0,      0 },    0x00B9 },       /* SUPERSCRIPT_ONE */
-  { { GDK_dead_circumflex,     GDK_2,  0,      0 },    0x00B2 },       /* SUPERSCRIPT_TWO */
-  { { GDK_dead_circumflex,     GDK_3,  0,      0 },    0x00B3 },       /* SUPERSCRIPT_THREE */
-  { { GDK_dead_circumflex,     GDK_A,  0,      0 },    0x00C2 },       /* LATIN_CAPITAL_LETTER_A_WITH_CIRCUMFLEX */
-  { { GDK_dead_circumflex,     GDK_E,  0,      0 },    0x00CA },       /* LATIN_CAPITAL_LETTER_E_WITH_CIRCUMFLEX */
-  { { GDK_dead_circumflex,     GDK_I,  0,      0 },    0x00CE },       /* LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX */
-  { { GDK_dead_circumflex,     GDK_O,  0,      0 },    0x00D4 },       /* LATIN_CAPITAL_LETTER_O_WITH_CIRCUMFLEX */
-  { { GDK_dead_circumflex,     GDK_U,  0,      0 },    0x00DB },       /* LATIN_CAPITAL_LETTER_U_WITH_CIRCUMFLEX */
-  { { GDK_dead_circumflex,     GDK_underscore, 0,      0 },    0x00AF },       /* MACRON */
-  { { GDK_dead_circumflex,     GDK_a,  0,      0 },    0x00E2 },       /* LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX */
-  { { GDK_dead_circumflex,     GDK_e,  0,      0 },    0x00EA },       /* LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX */
-  { { GDK_dead_circumflex,     GDK_i,  0,      0 },    0x00EE },       /* LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX */
-  { { GDK_dead_circumflex,     GDK_o,  0,      0 },    0x00F4 },       /* LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX */
-  { { GDK_dead_circumflex,     GDK_u,  0,      0 },    0x00FB },       /* LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX */
-  { { GDK_dead_tilde,  GDK_space,      0,      0 },    0x007E },       /* TILDE */
-  { { GDK_dead_tilde,  GDK_A,  0,      0 },    0x00C3 },       /* LATIN_CAPITAL_LETTER_A_WITH_TILDE */
-  { { GDK_dead_tilde,  GDK_I,  0,      0 },    0x0128 },       /* LATIN_CAPITAL_LETTER_I_WITH_TILDE */
-  { { GDK_dead_tilde,  GDK_N,  0,      0 },    0x00D1 },       /* LATIN_CAPITAL_LETTER_N_WITH_TILDE */
-  { { GDK_dead_tilde,  GDK_O,  0,      0 },    0x00D5 },       /* LATIN_CAPITAL_LETTER_O_WITH_TILDE */
-  { { GDK_dead_tilde,  GDK_U,  0,      0 },    0x0168 },       /* LATIN_CAPITAL_LETTER_U_WITH_TILDE */
-  { { GDK_dead_tilde,  GDK_a,  0,      0 },    0x00E3 },       /* LATIN_SMALL_LETTER_A_WITH_TILDE */
-  { { GDK_dead_tilde,  GDK_i,  0,      0 },    0x0129 },       /* LATIN_SMALL_LETTER_I_WITH_TILDE */
-  { { GDK_dead_tilde,  GDK_n,  0,      0 },    0x00F1 },       /* LATIN_SMALL_LETTER_N_WITH_TILDE */
-  { { GDK_dead_tilde,  GDK_o,  0,      0 },    0x00F5 },       /* LATIN_SMALL_LETTER_O_WITH_TILDE */
-  { { GDK_dead_tilde,  GDK_u,  0,      0 },    0x0169 },       /* LATIN_SMALL_LETTER_U_WITH_TILDE */
-  { { GDK_dead_tilde,  GDK_asciitilde, 0,      0 },    0x007E },       /* TILDE */
-  { { GDK_dead_tilde,  GDK_dead_tilde, 0,      0 },    0x007E },       /* TILDE */
-  { { GDK_dead_macron, GDK_A,  0,      0 },    0x0100 },       /* LATIN_CAPITAL_LETTER_A_WITH_MACRON */
-  { { GDK_dead_macron, GDK_E,  0,      0 },    0x0112 },       /* LATIN_CAPITAL_LETTER_E_WITH_MACRON */
-  { { GDK_dead_macron, GDK_I,  0,      0 },    0x012A },       /* LATIN_CAPITAL_LETTER_I_WITH_MACRON */
-  { { GDK_dead_macron, GDK_O,  0,      0 },    0x014C },       /* LATIN_CAPITAL_LETTER_O_WITH_MACRON */
-  { { GDK_dead_macron, GDK_U,  0,      0 },    0x00D9 },       /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */
-  { { GDK_dead_macron, GDK_a,  0,      0 },    0x0101 },       /* LATIN_SMALL_LETTER_A_WITH_MACRON */
-  { { GDK_dead_macron, GDK_e,  0,      0 },    0x0113 },       /* LATIN_SMALL_LETTER_E_WITH_MACRON */
-  { { GDK_dead_macron, GDK_i,  0,      0 },    0x012B },       /* LATIN_SMALL_LETTER_I_WITH_MACRON */
-  { { GDK_dead_macron, GDK_o,  0,      0 },    0x014D },       /* LATIN_SMALL_LETTER_O_WITH_MACRON */
-  { { GDK_dead_macron, GDK_u,  0,      0 },    0x016B },       /* LATIN_SMALL_LETTER_U_WITH_MACRON */
-  { { GDK_dead_macron, GDK_macron,     0,      0 },    0x00AF },       /* MACRON */
-  { { GDK_dead_macron, GDK_dead_macron,        0,      0 },    0x00AF },       /* MACRON */
-  { { GDK_dead_breve,  GDK_G,  0,      0 },    0x011E },       /* LATIN_CAPITAL_LETTER_G_WITH_BREVE */
-  { { GDK_dead_breve,  GDK_g,  0,      0 },    0x011F },       /* LATIN_SMALL_LETTER_G_WITH_BREVE */
-  { { GDK_dead_abovedot,       GDK_E,  0,      0 },    0x0116 },       /* LATIN_CAPITAL_LETTER_E_WITH_DOT_ABOVE */
-  { { GDK_dead_abovedot,       GDK_I,  0,      0 },    0x0130 },       /* LATIN_CAPITAL_LETTER_I_WITH_DOT_ABOVE */
-  { { GDK_dead_abovedot,       GDK_e,  0,      0 },    0x0117 },       /* LATIN_SMALL_LETTER_E_WITH_DOT_ABOVE */
-  { { GDK_dead_abovedot,       GDK_i,  0,      0 },    0x0131 },       /* LATIN_SMALL_LETTER_DOTLESS_I */
-  { { GDK_dead_abovedot,       GDK_abovedot,   0,      0 },    0x02D9 },       /* DOT_ABOVE */
-  { { GDK_dead_abovedot,       GDK_dead_abovedot,      0,      0 },    0x02D9 },       /* DOT_ABOVE */
-  { { GDK_dead_diaeresis,      GDK_space,      0,      0 },    0x00A8 },       /* DIAERESIS */
-  { { GDK_dead_diaeresis,      GDK_quotedbl,   0,      0 },    0x00A8 },       /* DIAERESIS */
-  { { GDK_dead_diaeresis,      GDK_A,  0,      0 },    0x00C4 },       /* LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS */
-  { { GDK_dead_diaeresis,      GDK_E,  0,      0 },    0x00CB },       /* LATIN_CAPITAL_LETTER_E_WITH_DIAERESIS */
-  { { GDK_dead_diaeresis,      GDK_I,  0,      0 },    0x00CF },       /* LATIN_CAPITAL_LETTER_I_WITH_DIAERESIS */
-  { { GDK_dead_diaeresis,      GDK_O,  0,      0 },    0x00D6 },       /* LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS */
-  { { GDK_dead_diaeresis,      GDK_U,  0,      0 },    0x00DC },       /* LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS */
-  { { GDK_dead_diaeresis,      GDK_Y,  0,      0 },    0x0178 },       /* LATIN_CAPITAL_LETTER_Y_WITH_DIAERESIS */
-  { { GDK_dead_diaeresis,      GDK_a,  0,      0 },    0x00E4 },       /* LATIN_SMALL_LETTER_A_WITH_DIAERESIS */
-  { { GDK_dead_diaeresis,      GDK_e,  0,      0 },    0x00EB },       /* LATIN_SMALL_LETTER_E_WITH_DIAERESIS */
-  { { GDK_dead_diaeresis,      GDK_i,  0,      0 },    0x00EF },       /* LATIN_SMALL_LETTER_I_WITH_DIAERESIS */
-  { { GDK_dead_diaeresis,      GDK_o,  0,      0 },    0x00F6 },       /* LATIN_SMALL_LETTER_O_WITH_DIAERESIS */
-  { { GDK_dead_diaeresis,      GDK_u,  0,      0 },    0x00FC },       /* LATIN_SMALL_LETTER_U_WITH_DIAERESIS */
-  { { GDK_dead_diaeresis,      GDK_y,  0,      0 },    0x00FF },       /* LATIN_SMALL_LETTER_Y_WITH_DIAERESIS */
-  { { GDK_dead_diaeresis,      GDK_diaeresis,  0,      0 },    0x00A8 },       /* DIAERESIS */
-  { { GDK_dead_diaeresis,      GDK_dead_diaeresis,     0,      0 },    0x00A8 },       /* DIAERESIS */
-  { { GDK_dead_abovering,      GDK_A,  0,      0 },    0x00C5 },       /* LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE */
-  { { GDK_dead_abovering,      GDK_a,  0,      0 },    0x00E5 },       /* LATIN_SMALL_LETTER_A_WITH_RING_ABOVE */
-  { { GDK_dead_abovering,      GDK_dead_abovering,     0,      0 },    0x02DA },       /* RING_ABOVE */
-  { { GDK_dead_caron,  GDK_C,  0,      0 },    0x010C },       /* LATIN_CAPITAL_LETTER_C_WITH_CARON */
-  { { GDK_dead_caron,  GDK_S,  0,      0 },    0x0160 },       /* LATIN_CAPITAL_LETTER_S_WITH_CARON */
-  { { GDK_dead_caron,  GDK_Z,  0,      0 },    0x017D },       /* LATIN_CAPITAL_LETTER_Z_WITH_CARON */
-  { { GDK_dead_caron,  GDK_c,  0,      0 },    0x010D },       /* LATIN_SMALL_LETTER_C_WITH_CARON */
-  { { GDK_dead_caron,  GDK_s,  0,      0 },    0x0161 },       /* LATIN_SMALL_LETTER_S_WITH_CARON */
-  { { GDK_dead_caron,  GDK_z,  0,      0 },    0x017E },       /* LATIN_SMALL_LETTER_Z_WITH_CARON */
-  { { GDK_dead_caron,  GDK_caron,      0,      0 },    0x02C7 },       /* CARON */
-  { { GDK_dead_caron,  GDK_dead_caron, 0,      0 },    0x02C7 },       /* CARON */
-  { { GDK_dead_cedilla,        GDK_comma,      0,      0 },    0x00B8 },       /* CEDILLA */
-  { { GDK_dead_cedilla,        GDK_minus,      0,      0 },    0x00AC },       /* NOT_SIGN */
-  { { GDK_dead_cedilla,        GDK_C,  0,      0 },    0x00C7 },       /* LATIN_CAPITAL_LETTER_C_WITH_CEDILLA */
-  { { GDK_dead_cedilla,        GDK_G,  0,      0 },    0x0122 },       /* LATIN_CAPITAL_LETTER_G_WITH_CEDILLA */
-  { { GDK_dead_cedilla,        GDK_K,  0,      0 },    0x0136 },       /* LATIN_CAPITAL_LETTER_K_WITH_CEDILLA */
-  { { GDK_dead_cedilla,        GDK_L,  0,      0 },    0x013B },       /* LATIN_CAPITAL_LETTER_L_WITH_CEDILLA */
-  { { GDK_dead_cedilla,        GDK_N,  0,      0 },    0x0145 },       /* LATIN_CAPITAL_LETTER_N_WITH_CEDILLA */
-  { { GDK_dead_cedilla,        GDK_R,  0,      0 },    0x0156 },       /* LATIN_CAPITAL_LETTER_R_WITH_CEDILLA */
-  { { GDK_dead_cedilla,        GDK_S,  0,      0 },    0x015E },       /* LATIN_CAPITAL_LETTER_S_WITH_CEDILLA */
-  { { GDK_dead_cedilla,        GDK_c,  0,      0 },    0x00E7 },       /* LATIN_SMALL_LETTER_C_WITH_CEDILLA */
-  { { GDK_dead_cedilla,        GDK_g,  0,      0 },    0x0123 },       /* LATIN_SMALL_LETTER_G_WITH_CEDILLA */
-  { { GDK_dead_cedilla,        GDK_k,  0,      0 },    0x0137 },       /* LATIN_SMALL_LETTER_K_WITH_CEDILLA */
-  { { GDK_dead_cedilla,        GDK_l,  0,      0 },    0x013C },       /* LATIN_SMALL_LETTER_L_WITH_CEDILLA */
-  { { GDK_dead_cedilla,        GDK_n,  0,      0 },    0x0146 },       /* LATIN_SMALL_LETTER_N_WITH_CEDILLA */
-  { { GDK_dead_cedilla,        GDK_r,  0,      0 },    0x0157 },       /* LATIN_SMALL_LETTER_R_WITH_CEDILLA */
-  { { GDK_dead_cedilla,        GDK_s,  0,      0 },    0x015F },       /* LATIN_SMALL_LETTER_S_WITH_CEDILLA */
-  { { GDK_dead_cedilla,        GDK_cedilla,    0,      0 },    0x00B8 },       /* CEDILLA */
-  { { GDK_dead_cedilla,        GDK_dead_cedilla,       0,      0 },    0x00B8 },       /* CEDILLA */
-  { { GDK_dead_ogonek, GDK_A,  0,      0 },    0x0104 },       /* LATIN_CAPITAL_LETTER_A_WITH_OGONEK */
-  { { GDK_dead_ogonek, GDK_E,  0,      0 },    0x0118 },       /* LATIN_CAPITAL_LETTER_E_WITH_OGONEK */
-  { { GDK_dead_ogonek, GDK_I,  0,      0 },    0x012E },       /* LATIN_CAPITAL_LETTER_I_WITH_OGONEK */
-  { { GDK_dead_ogonek, GDK_U,  0,      0 },    0x0172 },       /* LATIN_CAPITAL_LETTER_U_WITH_OGONEK */
-  { { GDK_dead_ogonek, GDK_a,  0,      0 },    0x0105 },       /* LATIN_SMALL_LETTER_A_WITH_OGONEK */
-  { { GDK_dead_ogonek, GDK_e,  0,      0 },    0x0119 },       /* LATIN_SMALL_LETTER_E_WITH_OGONEK */
-  { { GDK_dead_ogonek, GDK_i,  0,      0 },    0x012F },       /* LATIN_SMALL_LETTER_I_WITH_OGONEK */
-  { { GDK_dead_ogonek, GDK_u,  0,      0 },    0x0173 },       /* LATIN_SMALL_LETTER_U_WITH_OGONEK */
-  { { GDK_dead_ogonek, GDK_ogonek,     0,      0 },    0x02DB },       /* OGONEK */
-  { { GDK_dead_ogonek, GDK_dead_ogonek,        0,      0 },    0x02DB },       /* OGONEK */
-  { { GDK_Multi_key,   GDK_space,      GDK_space,      0 },    0x00A0 },       /* NOxBREAK_SPACE */
-  { { GDK_Multi_key,   GDK_space,      GDK_apostrophe, 0 },    0x0027 },       /* APOSTROPHE */
-  { { GDK_Multi_key,   GDK_space,      GDK_minus,      0 },    0x007E },       /* TILDE */
-  { { GDK_Multi_key,   GDK_space,      GDK_greater,    0 },    0x005E },       /* CIRCUMFLEX_ACCENT */
-  { { GDK_Multi_key,   GDK_space,      GDK_asciicircum,        0 },    0x005E },       /* CIRCUMFLEX_ACCENT */
-  { { GDK_Multi_key,   GDK_space,      GDK_grave,      0 },    0x0060 },       /* GRAVE_ACCENT */
-  { { GDK_Multi_key,   GDK_space,      GDK_asciitilde, 0 },    0x007E },       /* TILDE */
-  { { GDK_Multi_key,   GDK_exclam,     GDK_exclam,     0 },    0x00A1 },       /* INVERTED_EXCLAMATION_MARK */
-  { { GDK_Multi_key,   GDK_exclam,     GDK_P,  0 },    0x00B6 },       /* PILCROW_SIGN */
-  { { GDK_Multi_key,   GDK_exclam,     GDK_S,  0 },    0x00A7 },       /* SECTION_SIGN */
-  { { GDK_Multi_key,   GDK_exclam,     GDK_p,  0 },    0x00B6 },       /* PILCROW_SIGN */
-  { { GDK_Multi_key,   GDK_exclam,     GDK_s,  0 },    0x00A7 },       /* SECTION_SIGN */
-  { { GDK_Multi_key,   GDK_quotedbl,   GDK_quotedbl,   0 },    0x00A8 },       /* DIAERESIS */
-  { { GDK_Multi_key,   GDK_quotedbl,   GDK_A,  0 },    0x00C4 },       /* LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_quotedbl,   GDK_E,  0 },    0x00CB },       /* LATIN_CAPITAL_LETTER_E_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_quotedbl,   GDK_I,  0 },    0x00CF },       /* LATIN_CAPITAL_LETTER_I_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_quotedbl,   GDK_O,  0 },    0x00D6 },       /* LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_quotedbl,   GDK_U,  0 },    0x00DC },       /* LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_quotedbl,   GDK_Y,  0 },    0x0178 },       /* LATIN_CAPITAL_LETTER_Y_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_quotedbl,   GDK_a,  0 },    0x00E4 },       /* LATIN_SMALL_LETTER_A_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_quotedbl,   GDK_e,  0 },    0x00EB },       /* LATIN_SMALL_LETTER_E_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_quotedbl,   GDK_i,  0 },    0x00EF },       /* LATIN_SMALL_LETTER_I_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_quotedbl,   GDK_o,  0 },    0x00F6 },       /* LATIN_SMALL_LETTER_O_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_quotedbl,   GDK_u,  0 },    0x00FC },       /* LATIN_SMALL_LETTER_U_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_quotedbl,   GDK_y,  0 },    0x00FF },       /* LATIN_SMALL_LETTER_Y_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_apostrophe, GDK_space,      0 },    0x0027 },       /* APOSTROPHE */
-  { { GDK_Multi_key,   GDK_apostrophe, GDK_apostrophe, 0 },    0x00B4 },       /* ACUTE_ACCENT */
-  { { GDK_Multi_key,   GDK_apostrophe, GDK_A,  0 },    0x00C1 },       /* LATIN_CAPITAL_LETTER_A_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_apostrophe, GDK_E,  0 },    0x00C9 },       /* LATIN_CAPITAL_LETTER_E_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_apostrophe, GDK_I,  0 },    0x00CD },       /* LATIN_CAPITAL_LETTER_I_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_apostrophe, GDK_O,  0 },    0x00D3 },       /* LATIN_CAPITAL_LETTER_O_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_apostrophe, GDK_U,  0 },    0x00DA },       /* LATIN_CAPITAL_LETTER_U_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_apostrophe, GDK_Y,  0 },    0x00DD },       /* LATIN_CAPITAL_LETTER_Y_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_apostrophe, GDK_a,  0 },    0x00E1 },       /* LATIN_SMALL_LETTER_A_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_apostrophe, GDK_e,  0 },    0x00E9 },       /* LATIN_SMALL_LETTER_E_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_apostrophe, GDK_i,  0 },    0x00ED },       /* LATIN_SMALL_LETTER_I_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_apostrophe, GDK_o,  0 },    0x00F3 },       /* LATIN_SMALL_LETTER_O_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_apostrophe, GDK_u,  0 },    0x00FA },       /* LATIN_SMALL_LETTER_U_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_apostrophe, GDK_y,  0 },    0x00FD },       /* LATIN_SMALL_LETTER_Y_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_parenleft,  GDK_parenleft,  0 },    0x005B },       /* LEFT_SQUARE_BRACKET */
-  { { GDK_Multi_key,   GDK_parenleft,  GDK_minus,      0 },    0x007B },       /* LEFT_CURLY_BRACKET */
-  { { GDK_Multi_key,   GDK_parenleft,  GDK_G,  0 },    0x011E },       /* LATIN_CAPITAL_LETTER_G_WITH_BREVE */
-  { { GDK_Multi_key,   GDK_parenleft,  GDK_c,  0 },    0x00A9 },       /* COPYRIGHT_SIGN */
-  { { GDK_Multi_key,   GDK_parenleft,  GDK_g,  0 },    0x011F },       /* LATIN_SMALL_LETTER_G_WITH_BREVE */
-  { { GDK_Multi_key,   GDK_parenleft,  GDK_r,  0 },    0x00AE },       /* REGISTERED_SIGN */
-  { { GDK_Multi_key,   GDK_parenright, GDK_parenright, 0 },    0x005D },       /* RIGHT_SQUARE_BRACKET */
-  { { GDK_Multi_key,   GDK_parenright, GDK_minus,      0 },    0x007D },       /* RIGHT_CURLY_BRACKET */
-  { { GDK_Multi_key,   GDK_asterisk,   GDK_0,  0 },    0x00B0 },       /* DEGREE_SIGN */
-  { { GDK_Multi_key,   GDK_asterisk,   GDK_A,  0 },    0x00C5 },       /* LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE */
-  { { GDK_Multi_key,   GDK_asterisk,   GDK_a,  0 },    0x00E5 },       /* LATIN_SMALL_LETTER_A_WITH_RING_ABOVE */
-  { { GDK_Multi_key,   GDK_plus,       GDK_plus,       0 },    0x0023 },       /* NUMBER_SIGN */
-  { { GDK_Multi_key,   GDK_plus,       GDK_minus,      0 },    0x00B1 },       /* PLUSxMINUS_SIGN */
-  { { GDK_Multi_key,   GDK_comma,      GDK_comma,      0 },    0x00B8 },       /* CEDILLA */
-  { { GDK_Multi_key,   GDK_comma,      GDK_minus,      0 },    0x00AC },       /* NOT_SIGN */
-  { { GDK_Multi_key,   GDK_comma,      GDK_A,  0 },    0x0104 },       /* LATIN_CAPITAL_LETTER_A_WITH_OGONEK */
-  { { GDK_Multi_key,   GDK_comma,      GDK_C,  0 },    0x00C7 },       /* LATIN_CAPITAL_LETTER_C_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_comma,      GDK_E,  0 },    0x0118 },       /* LATIN_CAPITAL_LETTER_E_WITH_OGONEK */
-  { { GDK_Multi_key,   GDK_comma,      GDK_G,  0 },    0x0122 },       /* LATIN_CAPITAL_LETTER_G_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_comma,      GDK_I,  0 },    0x012E },       /* LATIN_CAPITAL_LETTER_I_WITH_OGONEK */
-  { { GDK_Multi_key,   GDK_comma,      GDK_K,  0 },    0x0136 },       /* LATIN_CAPITAL_LETTER_K_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_comma,      GDK_L,  0 },    0x013B },       /* LATIN_CAPITAL_LETTER_L_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_comma,      GDK_N,  0 },    0x0145 },       /* LATIN_CAPITAL_LETTER_N_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_comma,      GDK_R,  0 },    0x0156 },       /* LATIN_CAPITAL_LETTER_R_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_comma,      GDK_S,  0 },    0x015E },       /* LATIN_CAPITAL_LETTER_S_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_comma,      GDK_U,  0 },    0x0172 },       /* LATIN_CAPITAL_LETTER_U_WITH_OGONEK */
-  { { GDK_Multi_key,   GDK_comma,      GDK_a,  0 },    0x0105 },       /* LATIN_SMALL_LETTER_A_WITH_OGONEK */
-  { { GDK_Multi_key,   GDK_comma,      GDK_c,  0 },    0x00E7 },       /* LATIN_SMALL_LETTER_C_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_comma,      GDK_e,  0 },    0x0119 },       /* LATIN_SMALL_LETTER_E_WITH_OGONEK */
-  { { GDK_Multi_key,   GDK_comma,      GDK_g,  0 },    0x0123 },       /* LATIN_SMALL_LETTER_G_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_comma,      GDK_i,  0 },    0x012F },       /* LATIN_SMALL_LETTER_I_WITH_OGONEK */
-  { { GDK_Multi_key,   GDK_comma,      GDK_k,  0 },    0x0137 },       /* LATIN_SMALL_LETTER_K_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_comma,      GDK_l,  0 },    0x013C },       /* LATIN_SMALL_LETTER_L_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_comma,      GDK_n,  0 },    0x0146 },       /* LATIN_SMALL_LETTER_N_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_comma,      GDK_r,  0 },    0x0157 },       /* LATIN_SMALL_LETTER_R_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_comma,      GDK_s,  0 },    0x015F },       /* LATIN_SMALL_LETTER_S_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_comma,      GDK_u,  0 },    0x0173 },       /* LATIN_SMALL_LETTER_U_WITH_OGONEK */
-  { { GDK_Multi_key,   GDK_minus,      GDK_space,      0 },    0x007E },       /* TILDE */
-  { { GDK_Multi_key,   GDK_minus,      GDK_parenleft,  0 },    0x007B },       /* LEFT_CURLY_BRACKET */
-  { { GDK_Multi_key,   GDK_minus,      GDK_parenright, 0 },    0x007D },       /* RIGHT_CURLY_BRACKET */
-  { { GDK_Multi_key,   GDK_minus,      GDK_plus,       0 },    0x00B1 },       /* PLUSxMINUS_SIGN */
-  { { GDK_Multi_key,   GDK_minus,      GDK_comma,      0 },    0x00AC },       /* NOT_SIGN */
-  { { GDK_Multi_key,   GDK_minus,      GDK_minus,      0 },    0x00AD },       /* SOFT_HYPHEN */
-  { { GDK_Multi_key,   GDK_minus,      GDK_colon,      0 },    0x00F7 },       /* DIVISION_SIGN */
-  { { GDK_Multi_key,   GDK_minus,      GDK_A,  0 },    0x00C3 },       /* LATIN_CAPITAL_LETTER_A_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_minus,      GDK_D,  0 },    0x0110 },       /* LATIN_CAPITAL_LETTER_D_WITH_STROKE */
-  { { GDK_Multi_key,   GDK_minus,      GDK_E,  0 },    0x0112 },       /* LATIN_CAPITAL_LETTER_E_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_minus,      GDK_I,  0 },    0x012A },       /* LATIN_CAPITAL_LETTER_I_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_minus,      GDK_L,  0 },    0x00A3 },       /* POUND_SIGN */
-  { { GDK_Multi_key,   GDK_minus,      GDK_N,  0 },    0x00D1 },       /* LATIN_CAPITAL_LETTER_N_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_minus,      GDK_O,  0 },    0x00D5 },       /* LATIN_CAPITAL_LETTER_O_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_minus,      GDK_U,  0 },    0x00D9 },       /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_minus,      GDK_Y,  0 },    0x00A5 },       /* YEN_SIGN */
-  { { GDK_Multi_key,   GDK_minus,      GDK_asciicircum,        0 },    0x00AF },       /* MACRON */
-  { { GDK_Multi_key,   GDK_minus,      GDK_a,  0 },    0x00E3 },       /* LATIN_SMALL_LETTER_A_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_minus,      GDK_d,  0 },    0x0111 },       /* LATIN_SMALL_LETTER_D_WITH_STROKE */
-  { { GDK_Multi_key,   GDK_minus,      GDK_e,  0 },    0x0113 },       /* LATIN_SMALL_LETTER_E_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_minus,      GDK_i,  0 },    0x012B },       /* LATIN_SMALL_LETTER_I_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_minus,      GDK_l,  0 },    0x00A3 },       /* POUND_SIGN */
-  { { GDK_Multi_key,   GDK_minus,      GDK_n,  0 },    0x00F1 },       /* LATIN_SMALL_LETTER_N_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_minus,      GDK_o,  0 },    0x00F5 },       /* LATIN_SMALL_LETTER_O_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_minus,      GDK_u,  0 },    0x016B },       /* LATIN_SMALL_LETTER_U_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_minus,      GDK_y,  0 },    0x00A5 },       /* YEN_SIGN */
-  { { GDK_Multi_key,   GDK_period,     GDK_period,     0 },    0x02D9 },       /* DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_B,  0 },    0x1E02 },       /* LATIN_CAPITAL_LETTER_B_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_C,  0 },    0x010A },       /* LATIN_CAPITAL_LETTER_C_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_D,  0 },    0x1E0A },       /* LATIN_CAPITAL_LETTER_D_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_E,  0 },    0x0116 },       /* LATIN_CAPITAL_LETTER_E_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_F,  0 },    0x1E1E },       /* LATIN_CAPITAL_LETTER_F_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_G,  0 },    0x0120 },       /* LATIN_CAPITAL_LETTER_G_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_I,  0 },    0x0130 },       /* LATIN_CAPITAL_LETTER_I_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_M,  0 },    0x1E40 },       /* LATIN_CAPITAL_LETTER_M_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_P,  0 },    0x1E56 },       /* LATIN_CAPITAL_LETTER_P_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_S,  0 },    0x1E60 },       /* LATIN_CAPITAL_LETTER_S_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_T,  0 },    0x1E6A },       /* LATIN_CAPITAL_LETTER_T_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_asciicircum,        0 },    0x00B7 },       /* MIDDLE_DOT */
-  { { GDK_Multi_key,   GDK_period,     GDK_b,  0 },    0x1E03 },       /* LATIN_SMALL_LETTER_B_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_c,  0 },    0x010B },       /* LATIN_SMALL_LETTER_C_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_d,  0 },    0x1E0B },       /* LATIN_SMALL_LETTER_D_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_e,  0 },    0x0117 },       /* LATIN_SMALL_LETTER_E_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_f,  0 },    0x1E1F },       /* LATIN_SMALL_LETTER_F_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_g,  0 },    0x0121 },       /* LATIN_SMALL_LETTER_G_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_i,  0 },    0x0131 },       /* LATIN_SMALL_LETTER_DOTLESS_I */
-  { { GDK_Multi_key,   GDK_period,     GDK_m,  0 },    0x1E41 },       /* LATIN_SMALL_LETTER_M_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_p,  0 },    0x1E57 },       /* LATIN_SMALL_LETTER_P_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_s,  0 },    0x1E61 },       /* LATIN_SMALL_LETTER_S_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_t,  0 },    0x1E6B },       /* LATIN_SMALL_LETTER_T_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_slash,      GDK_slash,      0 },    0x005C },       /* REVERSE_SOLIDUS */
-  { { GDK_Multi_key,   GDK_slash,      GDK_less,       0 },    0x005C },       /* REVERSE_SOLIDUS */
-  { { GDK_Multi_key,   GDK_slash,      GDK_C,  0 },    0x00A2 },       /* CENT_SIGN */
-  { { GDK_Multi_key,   GDK_slash,      GDK_O,  0 },    0x00D8 },       /* LATIN_CAPITAL_LETTER_O_WITH_STROKE */
-  { { GDK_Multi_key,   GDK_slash,      GDK_T,  0 },    0x0166 },       /* LATIN_CAPITAL_LETTER_T_WITH_STROKE */
-  { { GDK_Multi_key,   GDK_slash,      GDK_U,  0 },    0x00B5 },       /* MICRO_SIGN */
-  { { GDK_Multi_key,   GDK_slash,      GDK_asciicircum,        0 },    0x007C },       /* VERTICAL_LINE */
-  { { GDK_Multi_key,   GDK_slash,      GDK_c,  0 },    0x00A2 },       /* CENT_SIGN */
-  { { GDK_Multi_key,   GDK_slash,      GDK_o,  0 },    0x00F8 },       /* LATIN_SMALL_LETTER_O_WITH_STROKE */
-  { { GDK_Multi_key,   GDK_slash,      GDK_t,  0 },    0x0167 },       /* LATIN_SMALL_LETTER_T_WITH_STROKE */
-  { { GDK_Multi_key,   GDK_slash,      GDK_u,  0 },    0x00B5 },       /* MICRO_SIGN */
-  { { GDK_Multi_key,   GDK_0,  GDK_asterisk,   0 },    0x00B0 },       /* DEGREE_SIGN */
-  { { GDK_Multi_key,   GDK_0,  GDK_C,  0 },    0x00A9 },       /* COPYRIGHT_SIGN */
-  { { GDK_Multi_key,   GDK_0,  GDK_S,  0 },    0x00A7 },       /* SECTION_SIGN */
-  { { GDK_Multi_key,   GDK_0,  GDK_X,  0 },    0x00A4 },       /* CURRENCY_SIGN */
-  { { GDK_Multi_key,   GDK_0,  GDK_asciicircum,        0 },    0x00B0 },       /* DEGREE_SIGN */
-  { { GDK_Multi_key,   GDK_0,  GDK_c,  0 },    0x00A9 },       /* COPYRIGHT_SIGN */
-  { { GDK_Multi_key,   GDK_0,  GDK_s,  0 },    0x00A7 },       /* SECTION_SIGN */
-  { { GDK_Multi_key,   GDK_0,  GDK_x,  0 },    0x00A4 },       /* CURRENCY_SIGN */
-  { { GDK_Multi_key,   GDK_1,  GDK_S,  0 },    0x00B9 },       /* SUPERSCRIPT_ONE */
-  { { GDK_Multi_key,   GDK_1,  GDK_asciicircum,        0 },    0x00B9 },       /* SUPERSCRIPT_ONE */
-  { { GDK_Multi_key,   GDK_1,  GDK_s,  0 },    0x00B9 },       /* SUPERSCRIPT_ONE */
-  { { GDK_Multi_key,   GDK_2,  GDK_S,  0 },    0x00B2 },       /* SUPERSCRIPT_TWO */
-  { { GDK_Multi_key,   GDK_2,  GDK_asciicircum,        0 },    0x00B2 },       /* SUPERSCRIPT_TWO */
-  { { GDK_Multi_key,   GDK_2,  GDK_s,  0 },    0x00B2 },       /* SUPERSCRIPT_TWO */
-  { { GDK_Multi_key,   GDK_3,  GDK_S,  0 },    0x00B3 },       /* SUPERSCRIPT_THREE */
-  { { GDK_Multi_key,   GDK_3,  GDK_asciicircum,        0 },    0x00B3 },       /* SUPERSCRIPT_THREE */
-  { { GDK_Multi_key,   GDK_3,  GDK_s,  0 },    0x00B3 },       /* SUPERSCRIPT_THREE */
-  { { GDK_Multi_key,   GDK_colon,      GDK_minus,      0 },    0x00F7 },       /* DIVISION_SIGN */
-  { { GDK_Multi_key,   GDK_less,       GDK_slash,      0 },    0x005C },       /* REVERSE_SOLIDUS */
-  { { GDK_Multi_key,   GDK_less,       GDK_less,       0 },    0x00AB },       /* LEFTxPOINTING_DOUBLE_ANGLE_QUOTATION_MARK */
-  { { GDK_Multi_key,   GDK_less,       GDK_C,  0 },    0x010C },       /* LATIN_CAPITAL_LETTER_C_WITH_CARON */
-  { { GDK_Multi_key,   GDK_less,       GDK_S,  0 },    0x0160 },       /* LATIN_CAPITAL_LETTER_S_WITH_CARON */
-  { { GDK_Multi_key,   GDK_less,       GDK_Z,  0 },    0x017D },       /* LATIN_CAPITAL_LETTER_Z_WITH_CARON */
-  { { GDK_Multi_key,   GDK_less,       GDK_c,  0 },    0x010D },       /* LATIN_SMALL_LETTER_C_WITH_CARON */
-  { { GDK_Multi_key,   GDK_less,       GDK_s,  0 },    0x0161 },       /* LATIN_SMALL_LETTER_S_WITH_CARON */
-  { { GDK_Multi_key,   GDK_less,       GDK_z,  0 },    0x017E },       /* LATIN_SMALL_LETTER_Z_WITH_CARON */
-  { { GDK_Multi_key,   GDK_equal,      GDK_C,  0 },    0x20AC },       /* EURO_SIGN */
-  { { GDK_Multi_key,   GDK_equal,      GDK_L,  0 },    0x00A3 },       /* POUND_SIGN */
-  { { GDK_Multi_key,   GDK_equal,      GDK_Y,  0 },    0x00A5 },       /* YEN_SIGN */
-  { { GDK_Multi_key,   GDK_equal,      GDK_e,  0 },    0x20AC },       /* EURO_SIGN */
-  { { GDK_Multi_key,   GDK_equal,      GDK_l,  0 },    0x00A3 },       /* POUND_SIGN */
-  { { GDK_Multi_key,   GDK_equal,      GDK_y,  0 },    0x00A5 },       /* YEN_SIGN */
-  { { GDK_Multi_key,   GDK_greater,    GDK_space,      0 },    0x005E },       /* CIRCUMFLEX_ACCENT */
-  { { GDK_Multi_key,   GDK_greater,    GDK_greater,    0 },    0x00BB },       /* RIGHTxPOINTING_DOUBLE_ANGLE_QUOTATION_MARK */
-  { { GDK_Multi_key,   GDK_greater,    GDK_A,  0 },    0x00C2 },       /* LATIN_CAPITAL_LETTER_A_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_greater,    GDK_E,  0 },    0x00CA },       /* LATIN_CAPITAL_LETTER_E_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_greater,    GDK_I,  0 },    0x00CE },       /* LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_greater,    GDK_O,  0 },    0x00D4 },       /* LATIN_CAPITAL_LETTER_O_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_greater,    GDK_U,  0 },    0x00DB },       /* LATIN_CAPITAL_LETTER_U_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_greater,    GDK_a,  0 },    0x00E2 },       /* LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_greater,    GDK_e,  0 },    0x00EA },       /* LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_greater,    GDK_i,  0 },    0x00EE },       /* LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_greater,    GDK_o,  0 },    0x00F4 },       /* LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_greater,    GDK_u,  0 },    0x00FB },       /* LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_question,   GDK_question,   0 },    0x00BF },       /* INVERTED_QUESTION_MARK */
-  { { GDK_Multi_key,   GDK_A,  GDK_quotedbl,   0 },    0x00C4 },       /* LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_A,  GDK_apostrophe, 0 },    0x00C1 },       /* LATIN_CAPITAL_LETTER_A_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_A,  GDK_asterisk,   0 },    0x00C5 },       /* LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE */
-  { { GDK_Multi_key,   GDK_A,  GDK_comma,      0 },    0x0104 },       /* LATIN_CAPITAL_LETTER_A_WITH_OGONEK */
-  { { GDK_Multi_key,   GDK_A,  GDK_minus,      0 },    0x00C3 },       /* LATIN_CAPITAL_LETTER_A_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_A,  GDK_greater,    0 },    0x00C2 },       /* LATIN_CAPITAL_LETTER_A_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_A,  GDK_A,  0 },    0x00C5 },       /* LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE */
-  { { GDK_Multi_key,   GDK_A,  GDK_E,  0 },    0x00C6 },       /* LATIN_CAPITAL_LETTER_AE */
-  { { GDK_Multi_key,   GDK_A,  GDK_asciicircum,        0 },    0x00C2 },       /* LATIN_CAPITAL_LETTER_A_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_A,  GDK_underscore, 0 },    0x00AA },       /* FEMININE_ORDINAL_INDICATOR */
-  { { GDK_Multi_key,   GDK_A,  GDK_grave,      0 },    0x00C0 },       /* LATIN_CAPITAL_LETTER_A_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_A,  GDK_asciitilde, 0 },    0x00C3 },       /* LATIN_CAPITAL_LETTER_A_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_A,  GDK_diaeresis,  0 },    0x00C4 },       /* LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_A,  GDK_acute,      0 },    0x00C1 },       /* LATIN_CAPITAL_LETTER_A_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_B,  GDK_period,     0 },    0x1E02 },       /* LATIN_CAPITAL_LETTER_B_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_C,  GDK_comma,      0 },    0x00C7 },       /* LATIN_CAPITAL_LETTER_C_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_C,  GDK_period,     0 },    0x010A },       /* LATIN_CAPITAL_LETTER_C_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_C,  GDK_slash,      0 },    0x00A2 },       /* CENT_SIGN */
-  { { GDK_Multi_key,   GDK_C,  GDK_0,  0 },    0x00A9 },       /* COPYRIGHT_SIGN */
-  { { GDK_Multi_key,   GDK_C,  GDK_less,       0 },    0x010C },       /* LATIN_CAPITAL_LETTER_C_WITH_CARON */
-  { { GDK_Multi_key,   GDK_C,  GDK_equal,      0 },    0x20AC },       /* EURO_SIGN */
-  { { GDK_Multi_key,   GDK_C,  GDK_O,  0 },    0x00A9 },       /* COPYRIGHT_SIGN */
-  { { GDK_Multi_key,   GDK_C,  GDK_o,  0 },    0x00A9 },       /* COPYRIGHT_SIGN */
-  { { GDK_Multi_key,   GDK_C,  GDK_bar,        0 },    0x00A2 },       /* CENT_SIGN */
-  { { GDK_Multi_key,   GDK_D,  GDK_minus,      0 },    0x0110 },       /* LATIN_CAPITAL_LETTER_D_WITH_STROKE */
-  { { GDK_Multi_key,   GDK_D,  GDK_period,     0 },    0x1E0A },       /* LATIN_CAPITAL_LETTER_D_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_E,  GDK_quotedbl,   0 },    0x00CB },       /* LATIN_CAPITAL_LETTER_E_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_E,  GDK_apostrophe, 0 },    0x00C9 },       /* LATIN_CAPITAL_LETTER_E_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_E,  GDK_comma,      0 },    0x0118 },       /* LATIN_CAPITAL_LETTER_E_WITH_OGONEK */
-  { { GDK_Multi_key,   GDK_E,  GDK_minus,      0 },    0x0112 },       /* LATIN_CAPITAL_LETTER_E_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_E,  GDK_period,     0 },    0x0116 },       /* LATIN_CAPITAL_LETTER_E_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_E,  GDK_greater,    0 },    0x00CA },       /* LATIN_CAPITAL_LETTER_E_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_E,  GDK_asciicircum,        0 },    0x00CA },       /* LATIN_CAPITAL_LETTER_E_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_E,  GDK_underscore, 0 },    0x0112 },       /* LATIN_CAPITAL_LETTER_E_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_E,  GDK_grave,      0 },    0x00C8 },       /* LATIN_CAPITAL_LETTER_E_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_E,  GDK_diaeresis,  0 },    0x00CB },       /* LATIN_CAPITAL_LETTER_E_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_E,  GDK_acute,      0 },    0x00C9 },       /* LATIN_CAPITAL_LETTER_E_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_F,  GDK_period,     0 },    0x1E1E },       /* LATIN_CAPITAL_LETTER_F_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_G,  GDK_parenleft,  0 },    0x011E },       /* LATIN_CAPITAL_LETTER_G_WITH_BREVE */
-  { { GDK_Multi_key,   GDK_G,  GDK_comma,      0 },    0x0122 },       /* LATIN_CAPITAL_LETTER_G_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_G,  GDK_period,     0 },    0x0120 },       /* LATIN_CAPITAL_LETTER_G_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_G,  GDK_U,  0 },    0x011E },       /* LATIN_CAPITAL_LETTER_G_WITH_BREVE */
-  { { GDK_Multi_key,   GDK_G,  GDK_breve,      0 },    0x011E },       /* LATIN_CAPITAL_LETTER_G_WITH_BREVE */
-  { { GDK_Multi_key,   GDK_I,  GDK_quotedbl,   0 },    0x00CF },       /* LATIN_CAPITAL_LETTER_I_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_I,  GDK_apostrophe, 0 },    0x00CD },       /* LATIN_CAPITAL_LETTER_I_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_I,  GDK_comma,      0 },    0x012E },       /* LATIN_CAPITAL_LETTER_I_WITH_OGONEK */
-  { { GDK_Multi_key,   GDK_I,  GDK_minus,      0 },    0x012A },       /* LATIN_CAPITAL_LETTER_I_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_I,  GDK_period,     0 },    0x0130 },       /* LATIN_CAPITAL_LETTER_I_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_I,  GDK_greater,    0 },    0x00CE },       /* LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_I,  GDK_asciicircum,        0 },    0x00CE },       /* LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_I,  GDK_underscore, 0 },    0x012A },       /* LATIN_CAPITAL_LETTER_I_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_I,  GDK_grave,      0 },    0x00CC },       /* LATIN_CAPITAL_LETTER_I_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_I,  GDK_asciitilde, 0 },    0x0128 },       /* LATIN_CAPITAL_LETTER_I_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_I,  GDK_diaeresis,  0 },    0x00CF },       /* LATIN_CAPITAL_LETTER_I_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_I,  GDK_acute,      0 },    0x00CD },       /* LATIN_CAPITAL_LETTER_I_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_K,  GDK_comma,      0 },    0x0136 },       /* LATIN_CAPITAL_LETTER_K_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_L,  GDK_comma,      0 },    0x013B },       /* LATIN_CAPITAL_LETTER_L_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_L,  GDK_minus,      0 },    0x00A3 },       /* POUND_SIGN */
-  { { GDK_Multi_key,   GDK_L,  GDK_equal,      0 },    0x00A3 },       /* POUND_SIGN */
-  { { GDK_Multi_key,   GDK_L,  GDK_V,  0 },    0x007C },       /* VERTICAL_LINE */
-  { { GDK_Multi_key,   GDK_M,  GDK_period,     0 },    0x1E40 },       /* LATIN_CAPITAL_LETTER_M_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_N,  GDK_comma,      0 },    0x0145 },       /* LATIN_CAPITAL_LETTER_N_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_N,  GDK_minus,      0 },    0x00D1 },       /* LATIN_CAPITAL_LETTER_N_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_N,  GDK_G,  0 },    0x014A },       /* LATIN_CAPITAL_LETTER_ENG */
-  { { GDK_Multi_key,   GDK_N,  GDK_asciitilde, 0 },    0x00D1 },       /* LATIN_CAPITAL_LETTER_N_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_O,  GDK_quotedbl,   0 },    0x00D6 },       /* LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_O,  GDK_apostrophe, 0 },    0x00D3 },       /* LATIN_CAPITAL_LETTER_O_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_O,  GDK_minus,      0 },    0x00D5 },       /* LATIN_CAPITAL_LETTER_O_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_O,  GDK_slash,      0 },    0x00D8 },       /* LATIN_CAPITAL_LETTER_O_WITH_STROKE */
-  { { GDK_Multi_key,   GDK_O,  GDK_greater,    0 },    0x00D4 },       /* LATIN_CAPITAL_LETTER_O_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_O,  GDK_C,  0 },    0x00A9 },       /* COPYRIGHT_SIGN */
-  { { GDK_Multi_key,   GDK_O,  GDK_E,  0 },    0x0152 },       /* LATIN_CAPITAL_LIGATURE_OE */
-  { { GDK_Multi_key,   GDK_O,  GDK_R,  0 },    0x00AE },       /* REGISTERED_SIGN */
-  { { GDK_Multi_key,   GDK_O,  GDK_S,  0 },    0x00A7 },       /* SECTION_SIGN */
-  { { GDK_Multi_key,   GDK_O,  GDK_X,  0 },    0x00A4 },       /* CURRENCY_SIGN */
-  { { GDK_Multi_key,   GDK_O,  GDK_asciicircum,        0 },    0x00D4 },       /* LATIN_CAPITAL_LETTER_O_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_O,  GDK_underscore, 0 },    0x00BA },       /* MASCULINE_ORDINAL_INDICATOR */
-  { { GDK_Multi_key,   GDK_O,  GDK_grave,      0 },    0x00D2 },       /* LATIN_CAPITAL_LETTER_O_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_O,  GDK_c,  0 },    0x00A9 },       /* COPYRIGHT_SIGN */
-  { { GDK_Multi_key,   GDK_O,  GDK_x,  0 },    0x00A4 },       /* CURRENCY_SIGN */
-  { { GDK_Multi_key,   GDK_O,  GDK_asciitilde, 0 },    0x00D5 },       /* LATIN_CAPITAL_LETTER_O_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_O,  GDK_diaeresis,  0 },    0x00D6 },       /* LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_O,  GDK_acute,      0 },    0x00D3 },       /* LATIN_CAPITAL_LETTER_O_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_P,  GDK_exclam,     0 },    0x00B6 },       /* PILCROW_SIGN */
-  { { GDK_Multi_key,   GDK_P,  GDK_period,     0 },    0x1E56 },       /* LATIN_CAPITAL_LETTER_P_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_R,  GDK_comma,      0 },    0x0156 },       /* LATIN_CAPITAL_LETTER_R_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_R,  GDK_O,  0 },    0x00AE },       /* REGISTERED_SIGN */
-  { { GDK_Multi_key,   GDK_S,  GDK_exclam,     0 },    0x00A7 },       /* SECTION_SIGN */
-  { { GDK_Multi_key,   GDK_S,  GDK_comma,      0 },    0x015E },       /* LATIN_CAPITAL_LETTER_S_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_S,  GDK_period,     0 },    0x1E60 },       /* LATIN_CAPITAL_LETTER_S_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_S,  GDK_0,  0 },    0x00A7 },       /* SECTION_SIGN */
-  { { GDK_Multi_key,   GDK_S,  GDK_1,  0 },    0x00B9 },       /* SUPERSCRIPT_ONE */
-  { { GDK_Multi_key,   GDK_S,  GDK_2,  0 },    0x00B2 },       /* SUPERSCRIPT_TWO */
-  { { GDK_Multi_key,   GDK_S,  GDK_3,  0 },    0x00B3 },       /* SUPERSCRIPT_THREE */
-  { { GDK_Multi_key,   GDK_S,  GDK_less,       0 },    0x0160 },       /* LATIN_CAPITAL_LETTER_S_WITH_CARON */
-  { { GDK_Multi_key,   GDK_S,  GDK_O,  0 },    0x00A7 },       /* SECTION_SIGN */
-  { { GDK_Multi_key,   GDK_S,  GDK_cedilla,    0 },    0x015E },       /* LATIN_CAPITAL_LETTER_S_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_T,  GDK_minus,      0 },    0x0166 },       /* LATIN_CAPITAL_LETTER_T_WITH_STROKE */
-  { { GDK_Multi_key,   GDK_T,  GDK_period,     0 },    0x1E6A },       /* LATIN_CAPITAL_LETTER_T_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_T,  GDK_slash,      0 },    0x0166 },       /* LATIN_CAPITAL_LETTER_T_WITH_STROKE */
-  { { GDK_Multi_key,   GDK_T,  GDK_H,  0 },    0x00DE },       /* LATIN_CAPITAL_LETTER_THORN */
-  { { GDK_Multi_key,   GDK_U,  GDK_quotedbl,   0 },    0x00DC },       /* LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_U,  GDK_apostrophe, 0 },    0x00DA },       /* LATIN_CAPITAL_LETTER_U_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_U,  GDK_comma,      0 },    0x0172 },       /* LATIN_CAPITAL_LETTER_U_WITH_OGONEK */
-  { { GDK_Multi_key,   GDK_U,  GDK_minus,      0 },    0x00D9 },       /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_U,  GDK_slash,      0 },    0x00B5 },       /* MICRO_SIGN */
-  { { GDK_Multi_key,   GDK_U,  GDK_greater,    0 },    0x00DB },       /* LATIN_CAPITAL_LETTER_U_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_U,  GDK_asciicircum,        0 },    0x00DB },       /* LATIN_CAPITAL_LETTER_U_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_U,  GDK_underscore, 0 },    0x00D9 },       /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_U,  GDK_grave,      0 },    0x00D9 },       /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_U,  GDK_asciitilde, 0 },    0x0168 },       /* LATIN_CAPITAL_LETTER_U_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_U,  GDK_diaeresis,  0 },    0x00DC },       /* LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_U,  GDK_acute,      0 },    0x00DA },       /* LATIN_CAPITAL_LETTER_U_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_V,  GDK_L,  0 },    0x007C },       /* VERTICAL_LINE */
-  { { GDK_Multi_key,   GDK_W,  GDK_asciicircum,        0 },    0x0174 },       /* LATIN_CAPITAL_LETTER_W_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_X,  GDK_0,  0 },    0x00A4 },       /* CURRENCY_SIGN */
-  { { GDK_Multi_key,   GDK_X,  GDK_O,  0 },    0x00A4 },       /* CURRENCY_SIGN */
-  { { GDK_Multi_key,   GDK_X,  GDK_o,  0 },    0x00A4 },       /* CURRENCY_SIGN */
-  { { GDK_Multi_key,   GDK_Y,  GDK_quotedbl,   0 },    0x0178 },       /* LATIN_CAPITAL_LETTER_Y_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_Y,  GDK_apostrophe, 0 },    0x00DD },       /* LATIN_CAPITAL_LETTER_Y_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_Y,  GDK_minus,      0 },    0x00A5 },       /* YEN_SIGN */
-  { { GDK_Multi_key,   GDK_Y,  GDK_equal,      0 },    0x00A5 },       /* YEN_SIGN */
-  { { GDK_Multi_key,   GDK_Y,  GDK_asciicircum,        0 },    0x0176 },       /* LATIN_CAPITAL_LETTER_Y_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_Y,  GDK_diaeresis,  0 },    0x0178 },       /* LATIN_CAPITAL_LETTER_Y_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_Y,  GDK_acute,      0 },    0x00DD },       /* LATIN_CAPITAL_LETTER_Y_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_Z,  GDK_less,       0 },    0x017D },       /* LATIN_CAPITAL_LETTER_Z_WITH_CARON */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_space,      0 },    0x005E },       /* CIRCUMFLEX_ACCENT */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_minus,      0 },    0x00AF },       /* MACRON */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_period,     0 },    0x00B7 },       /* MIDDLE_DOT */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_slash,      0 },    0x007C },       /* VERTICAL_LINE */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_0,  0 },    0x00B0 },       /* DEGREE_SIGN */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_1,  0 },    0x00B9 },       /* SUPERSCRIPT_ONE */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_2,  0 },    0x00B2 },       /* SUPERSCRIPT_TWO */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_3,  0 },    0x00B3 },       /* SUPERSCRIPT_THREE */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_A,  0 },    0x00C2 },       /* LATIN_CAPITAL_LETTER_A_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_E,  0 },    0x00CA },       /* LATIN_CAPITAL_LETTER_E_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_I,  0 },    0x00CE },       /* LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_O,  0 },    0x00D4 },       /* LATIN_CAPITAL_LETTER_O_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_U,  0 },    0x00DB },       /* LATIN_CAPITAL_LETTER_U_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_W,  0 },    0x0174 },       /* LATIN_CAPITAL_LETTER_W_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_Y,  0 },    0x0176 },       /* LATIN_CAPITAL_LETTER_Y_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_underscore, 0 },    0x00AF },       /* MACRON */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_a,  0 },    0x00E2 },       /* LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_e,  0 },    0x00EA },       /* LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_i,  0 },    0x00EE },       /* LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_o,  0 },    0x00F4 },       /* LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_u,  0 },    0x00FB },       /* LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_w,  0 },    0x0175 },       /* LATIN_SMALL_LETTER_W_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_y,  0 },    0x0177 },       /* LATIN_SMALL_LETTER_Y_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_underscore, GDK_A,  0 },    0x00AA },       /* FEMININE_ORDINAL_INDICATOR */
-  { { GDK_Multi_key,   GDK_underscore, GDK_E,  0 },    0x0112 },       /* LATIN_CAPITAL_LETTER_E_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_underscore, GDK_I,  0 },    0x012A },       /* LATIN_CAPITAL_LETTER_I_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_underscore, GDK_O,  0 },    0x00BA },       /* MASCULINE_ORDINAL_INDICATOR */
-  { { GDK_Multi_key,   GDK_underscore, GDK_U,  0 },    0x00D9 },       /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_underscore, GDK_asciicircum,        0 },    0x00AF },       /* MACRON */
-  { { GDK_Multi_key,   GDK_underscore, GDK_underscore, 0 },    0x00AF },       /* MACRON */
-  { { GDK_Multi_key,   GDK_underscore, GDK_a,  0 },    0x00AA },       /* FEMININE_ORDINAL_INDICATOR */
-  { { GDK_Multi_key,   GDK_underscore, GDK_e,  0 },    0x0113 },       /* LATIN_SMALL_LETTER_E_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_underscore, GDK_i,  0 },    0x012B },       /* LATIN_SMALL_LETTER_I_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_underscore, GDK_o,  0 },    0x00BA },       /* MASCULINE_ORDINAL_INDICATOR */
-  { { GDK_Multi_key,   GDK_underscore, GDK_u,  0 },    0x016B },       /* LATIN_SMALL_LETTER_U_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_grave,      GDK_space,      0 },    0x0060 },       /* GRAVE_ACCENT */
-  { { GDK_Multi_key,   GDK_grave,      GDK_A,  0 },    0x00C0 },       /* LATIN_CAPITAL_LETTER_A_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_grave,      GDK_E,  0 },    0x00C8 },       /* LATIN_CAPITAL_LETTER_E_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_grave,      GDK_I,  0 },    0x00CC },       /* LATIN_CAPITAL_LETTER_I_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_grave,      GDK_O,  0 },    0x00D2 },       /* LATIN_CAPITAL_LETTER_O_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_grave,      GDK_U,  0 },    0x00D9 },       /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_grave,      GDK_a,  0 },    0x00E0 },       /* LATIN_SMALL_LETTER_A_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_grave,      GDK_e,  0 },    0x00E8 },       /* LATIN_SMALL_LETTER_E_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_grave,      GDK_i,  0 },    0x00EC },       /* LATIN_SMALL_LETTER_I_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_grave,      GDK_o,  0 },    0x00F2 },       /* LATIN_SMALL_LETTER_O_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_grave,      GDK_u,  0 },    0x00F9 },       /* LATIN_SMALL_LETTER_U_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_a,  GDK_quotedbl,   0 },    0x00E4 },       /* LATIN_SMALL_LETTER_A_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_a,  GDK_apostrophe, 0 },    0x00E1 },       /* LATIN_SMALL_LETTER_A_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_a,  GDK_asterisk,   0 },    0x00E5 },       /* LATIN_SMALL_LETTER_A_WITH_RING_ABOVE */
-  { { GDK_Multi_key,   GDK_a,  GDK_comma,      0 },    0x0105 },       /* LATIN_SMALL_LETTER_A_WITH_OGONEK */
-  { { GDK_Multi_key,   GDK_a,  GDK_minus,      0 },    0x00E3 },       /* LATIN_SMALL_LETTER_A_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_a,  GDK_greater,    0 },    0x00E2 },       /* LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_a,  GDK_asciicircum,        0 },    0x00E2 },       /* LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_a,  GDK_underscore, 0 },    0x00AA },       /* FEMININE_ORDINAL_INDICATOR */
-  { { GDK_Multi_key,   GDK_a,  GDK_grave,      0 },    0x00E0 },       /* LATIN_SMALL_LETTER_A_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_a,  GDK_a,  0 },    0x00E5 },       /* LATIN_SMALL_LETTER_A_WITH_RING_ABOVE */
-  { { GDK_Multi_key,   GDK_a,  GDK_e,  0 },    0x00E6 },       /* LATIN_SMALL_LETTER_AE */
-  { { GDK_Multi_key,   GDK_a,  GDK_asciitilde, 0 },    0x00E3 },       /* LATIN_SMALL_LETTER_A_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_a,  GDK_diaeresis,  0 },    0x00E4 },       /* LATIN_SMALL_LETTER_A_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_a,  GDK_acute,      0 },    0x00E1 },       /* LATIN_SMALL_LETTER_A_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_b,  GDK_period,     0 },    0x1E03 },       /* LATIN_SMALL_LETTER_B_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_c,  GDK_comma,      0 },    0x00E7 },       /* LATIN_SMALL_LETTER_C_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_c,  GDK_period,     0 },    0x010B },       /* LATIN_SMALL_LETTER_C_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_c,  GDK_slash,      0 },    0x00A2 },       /* CENT_SIGN */
-  { { GDK_Multi_key,   GDK_c,  GDK_0,  0 },    0x00A9 },       /* COPYRIGHT_SIGN */
-  { { GDK_Multi_key,   GDK_c,  GDK_less,       0 },    0x010D },       /* LATIN_SMALL_LETTER_C_WITH_CARON */
-  { { GDK_Multi_key,   GDK_c,  GDK_O,  0 },    0x00A9 },       /* COPYRIGHT_SIGN */
-  { { GDK_Multi_key,   GDK_c,  GDK_o,  0 },    0x00A9 },       /* COPYRIGHT_SIGN */
-  { { GDK_Multi_key,   GDK_c,  GDK_bar,        0 },    0x00A2 },       /* CENT_SIGN */
-  { { GDK_Multi_key,   GDK_d,  GDK_minus,      0 },    0x0111 },       /* LATIN_SMALL_LETTER_D_WITH_STROKE */
-  { { GDK_Multi_key,   GDK_d,  GDK_period,     0 },    0x1E0B },       /* LATIN_SMALL_LETTER_D_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_e,  GDK_quotedbl,   0 },    0x00EB },       /* LATIN_SMALL_LETTER_E_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_e,  GDK_apostrophe, 0 },    0x00E9 },       /* LATIN_SMALL_LETTER_E_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_e,  GDK_comma,      0 },    0x0119 },       /* LATIN_SMALL_LETTER_E_WITH_OGONEK */
-  { { GDK_Multi_key,   GDK_e,  GDK_minus,      0 },    0x0113 },       /* LATIN_SMALL_LETTER_E_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_e,  GDK_period,     0 },    0x0117 },       /* LATIN_SMALL_LETTER_E_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_e,  GDK_equal,      0 },    0x20AC },       /* EURO_SIGN */
-  { { GDK_Multi_key,   GDK_e,  GDK_greater,    0 },    0x00EA },       /* LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_e,  GDK_asciicircum,        0 },    0x00EA },       /* LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_e,  GDK_underscore, 0 },    0x0113 },       /* LATIN_SMALL_LETTER_E_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_e,  GDK_grave,      0 },    0x00E8 },       /* LATIN_SMALL_LETTER_E_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_e,  GDK_diaeresis,  0 },    0x00EB },       /* LATIN_SMALL_LETTER_E_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_e,  GDK_acute,      0 },    0x00E9 },       /* LATIN_SMALL_LETTER_E_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_f,  GDK_period,     0 },    0x1E1F },       /* LATIN_SMALL_LETTER_F_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_g,  GDK_parenleft,  0 },    0x011F },       /* LATIN_SMALL_LETTER_G_WITH_BREVE */
-  { { GDK_Multi_key,   GDK_g,  GDK_comma,      0 },    0x0123 },       /* LATIN_SMALL_LETTER_G_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_g,  GDK_period,     0 },    0x0121 },       /* LATIN_SMALL_LETTER_G_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_g,  GDK_U,  0 },    0x011F },       /* LATIN_SMALL_LETTER_G_WITH_BREVE */
-  { { GDK_Multi_key,   GDK_g,  GDK_breve,      0 },    0x011F },       /* LATIN_SMALL_LETTER_G_WITH_BREVE */
-  { { GDK_Multi_key,   GDK_i,  GDK_quotedbl,   0 },    0x00EF },       /* LATIN_SMALL_LETTER_I_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_i,  GDK_apostrophe, 0 },    0x00ED },       /* LATIN_SMALL_LETTER_I_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_i,  GDK_comma,      0 },    0x012F },       /* LATIN_SMALL_LETTER_I_WITH_OGONEK */
-  { { GDK_Multi_key,   GDK_i,  GDK_minus,      0 },    0x012B },       /* LATIN_SMALL_LETTER_I_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_i,  GDK_period,     0 },    0x0131 },       /* LATIN_SMALL_LETTER_DOTLESS_I */
-  { { GDK_Multi_key,   GDK_i,  GDK_greater,    0 },    0x00EE },       /* LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_i,  GDK_asciicircum,        0 },    0x00EE },       /* LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_i,  GDK_underscore, 0 },    0x012B },       /* LATIN_SMALL_LETTER_I_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_i,  GDK_grave,      0 },    0x00EC },       /* LATIN_SMALL_LETTER_I_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_i,  GDK_asciitilde, 0 },    0x0129 },       /* LATIN_SMALL_LETTER_I_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_i,  GDK_diaeresis,  0 },    0x00EF },       /* LATIN_SMALL_LETTER_I_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_i,  GDK_acute,      0 },    0x00ED },       /* LATIN_SMALL_LETTER_I_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_k,  GDK_comma,      0 },    0x0137 },       /* LATIN_SMALL_LETTER_K_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_k,  GDK_k,  0 },    0x0138 },       /* LATIN_SMALL_LETTER_KRA */
-  { { GDK_Multi_key,   GDK_l,  GDK_comma,      0 },    0x013C },       /* LATIN_SMALL_LETTER_L_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_l,  GDK_minus,      0 },    0x00A3 },       /* POUND_SIGN */
-  { { GDK_Multi_key,   GDK_l,  GDK_equal,      0 },    0x00A3 },       /* POUND_SIGN */
-  { { GDK_Multi_key,   GDK_l,  GDK_v,  0 },    0x007C },       /* VERTICAL_LINE */
-  { { GDK_Multi_key,   GDK_m,  GDK_period,     0 },    0x1E41 },       /* LATIN_SMALL_LETTER_M_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_n,  GDK_comma,      0 },    0x0146 },       /* LATIN_SMALL_LETTER_N_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_n,  GDK_minus,      0 },    0x00F1 },       /* LATIN_SMALL_LETTER_N_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_n,  GDK_g,  0 },    0x014B },       /* LATIN_SMALL_LETTER_ENG */
-  { { GDK_Multi_key,   GDK_n,  GDK_asciitilde, 0 },    0x00F1 },       /* LATIN_SMALL_LETTER_N_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_o,  GDK_quotedbl,   0 },    0x00F6 },       /* LATIN_SMALL_LETTER_O_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_o,  GDK_apostrophe, 0 },    0x00F3 },       /* LATIN_SMALL_LETTER_O_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_o,  GDK_minus,      0 },    0x00F5 },       /* LATIN_SMALL_LETTER_O_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_o,  GDK_slash,      0 },    0x00F8 },       /* LATIN_SMALL_LETTER_O_WITH_STROKE */
-  { { GDK_Multi_key,   GDK_o,  GDK_greater,    0 },    0x00F4 },       /* LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_o,  GDK_C,  0 },    0x00A9 },       /* COPYRIGHT_SIGN */
-  { { GDK_Multi_key,   GDK_o,  GDK_X,  0 },    0x00A4 },       /* CURRENCY_SIGN */
-  { { GDK_Multi_key,   GDK_o,  GDK_asciicircum,        0 },    0x00F4 },       /* LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_o,  GDK_underscore, 0 },    0x00BA },       /* MASCULINE_ORDINAL_INDICATOR */
-  { { GDK_Multi_key,   GDK_o,  GDK_grave,      0 },    0x00F2 },       /* LATIN_SMALL_LETTER_O_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_o,  GDK_c,  0 },    0x00A9 },       /* COPYRIGHT_SIGN */
-  { { GDK_Multi_key,   GDK_o,  GDK_e,  0 },    0x0153 },       /* LATIN_SMALL_LIGATURE_OE */
-  { { GDK_Multi_key,   GDK_o,  GDK_s,  0 },    0x00A7 },       /* SECTION_SIGN */
-  { { GDK_Multi_key,   GDK_o,  GDK_x,  0 },    0x00A4 },       /* CURRENCY_SIGN */
-  { { GDK_Multi_key,   GDK_o,  GDK_asciitilde, 0 },    0x00F5 },       /* LATIN_SMALL_LETTER_O_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_o,  GDK_diaeresis,  0 },    0x00F6 },       /* LATIN_SMALL_LETTER_O_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_o,  GDK_acute,      0 },    0x00F3 },       /* LATIN_SMALL_LETTER_O_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_p,  GDK_exclam,     0 },    0x00B6 },       /* PILCROW_SIGN */
-  { { GDK_Multi_key,   GDK_p,  GDK_period,     0 },    0x1E57 },       /* LATIN_SMALL_LETTER_P_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_r,  GDK_comma,      0 },    0x0157 },       /* LATIN_SMALL_LETTER_R_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_s,  GDK_exclam,     0 },    0x00A7 },       /* SECTION_SIGN */
-  { { GDK_Multi_key,   GDK_s,  GDK_comma,      0 },    0x015F },       /* LATIN_SMALL_LETTER_S_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_s,  GDK_period,     0 },    0x1E61 },       /* LATIN_SMALL_LETTER_S_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_s,  GDK_0,  0 },    0x00A7 },       /* SECTION_SIGN */
-  { { GDK_Multi_key,   GDK_s,  GDK_1,  0 },    0x00B9 },       /* SUPERSCRIPT_ONE */
-  { { GDK_Multi_key,   GDK_s,  GDK_2,  0 },    0x00B2 },       /* SUPERSCRIPT_TWO */
-  { { GDK_Multi_key,   GDK_s,  GDK_3,  0 },    0x00B3 },       /* SUPERSCRIPT_THREE */
-  { { GDK_Multi_key,   GDK_s,  GDK_less,       0 },    0x0161 },       /* LATIN_SMALL_LETTER_S_WITH_CARON */
-  { { GDK_Multi_key,   GDK_s,  GDK_o,  0 },    0x00A7 },       /* SECTION_SIGN */
-  { { GDK_Multi_key,   GDK_s,  GDK_s,  0 },    0x00DF },       /* LATIN_SMALL_LETTER_SHARP_S */
-  { { GDK_Multi_key,   GDK_s,  GDK_cedilla,    0 },    0x015F },       /* LATIN_SMALL_LETTER_S_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_t,  GDK_minus,      0 },    0x0167 },       /* LATIN_SMALL_LETTER_T_WITH_STROKE */
-  { { GDK_Multi_key,   GDK_t,  GDK_period,     0 },    0x1E6B },       /* LATIN_SMALL_LETTER_T_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_t,  GDK_slash,      0 },    0x0167 },       /* LATIN_SMALL_LETTER_T_WITH_STROKE */
-  { { GDK_Multi_key,   GDK_t,  GDK_h,  0 },    0x00FE },       /* LATIN_SMALL_LETTER_THORN */
-  { { GDK_Multi_key,   GDK_u,  GDK_quotedbl,   0 },    0x00FC },       /* LATIN_SMALL_LETTER_U_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_u,  GDK_apostrophe, 0 },    0x00FA },       /* LATIN_SMALL_LETTER_U_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_u,  GDK_comma,      0 },    0x0173 },       /* LATIN_SMALL_LETTER_U_WITH_OGONEK */
-  { { GDK_Multi_key,   GDK_u,  GDK_minus,      0 },    0x016B },       /* LATIN_SMALL_LETTER_U_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_u,  GDK_slash,      0 },    0x00B5 },       /* MICRO_SIGN */
-  { { GDK_Multi_key,   GDK_u,  GDK_greater,    0 },    0x00FB },       /* LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_u,  GDK_asciicircum,        0 },    0x00FB },       /* LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_u,  GDK_underscore, 0 },    0x016B },       /* LATIN_SMALL_LETTER_U_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_u,  GDK_grave,      0 },    0x00F9 },       /* LATIN_SMALL_LETTER_U_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_u,  GDK_asciitilde, 0 },    0x0169 },       /* LATIN_SMALL_LETTER_U_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_u,  GDK_diaeresis,  0 },    0x00FC },       /* LATIN_SMALL_LETTER_U_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_u,  GDK_acute,      0 },    0x00FA },       /* LATIN_SMALL_LETTER_U_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_v,  GDK_Z,  0 },    0x017D },       /* LATIN_CAPITAL_LETTER_Z_WITH_CARON */
-  { { GDK_Multi_key,   GDK_v,  GDK_l,  0 },    0x007C },       /* VERTICAL_LINE */
-  { { GDK_Multi_key,   GDK_v,  GDK_z,  0 },    0x017E },       /* LATIN_SMALL_LETTER_Z_WITH_CARON */
-  { { GDK_Multi_key,   GDK_w,  GDK_asciicircum,        0 },    0x0175 },       /* LATIN_SMALL_LETTER_W_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_x,  GDK_0,  0 },    0x00A4 },       /* CURRENCY_SIGN */
-  { { GDK_Multi_key,   GDK_x,  GDK_O,  0 },    0x00A4 },       /* CURRENCY_SIGN */
-  { { GDK_Multi_key,   GDK_x,  GDK_o,  0 },    0x00A4 },       /* CURRENCY_SIGN */
-  { { GDK_Multi_key,   GDK_x,  GDK_x,  0 },    0x00D7 },       /* MULTIPLICATION_SIGN */
-  { { GDK_Multi_key,   GDK_y,  GDK_quotedbl,   0 },    0x00FF },       /* LATIN_SMALL_LETTER_Y_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_y,  GDK_apostrophe, 0 },    0x00FD },       /* LATIN_SMALL_LETTER_Y_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_y,  GDK_minus,      0 },    0x00A5 },       /* YEN_SIGN */
-  { { GDK_Multi_key,   GDK_y,  GDK_equal,      0 },    0x00A5 },       /* YEN_SIGN */
-  { { GDK_Multi_key,   GDK_y,  GDK_asciicircum,        0 },    0x0177 },       /* LATIN_SMALL_LETTER_Y_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_y,  GDK_diaeresis,  0 },    0x00FF },       /* LATIN_SMALL_LETTER_Y_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_y,  GDK_acute,      0 },    0x00FD },       /* LATIN_SMALL_LETTER_Y_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_z,  GDK_less,       0 },    0x017E },       /* LATIN_SMALL_LETTER_Z_WITH_CARON */
-  { { GDK_Multi_key,   GDK_bar,        GDK_C,  0 },    0x00A2 },       /* CENT_SIGN */
-  { { GDK_Multi_key,   GDK_bar,        GDK_c,  0 },    0x00A2 },       /* CENT_SIGN */
-  { { GDK_Multi_key,   GDK_asciitilde, GDK_space,      0 },    0x007E },       /* TILDE */
-  { { GDK_Multi_key,   GDK_asciitilde, GDK_A,  0 },    0x00C3 },       /* LATIN_CAPITAL_LETTER_A_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_asciitilde, GDK_I,  0 },    0x0128 },       /* LATIN_CAPITAL_LETTER_I_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_asciitilde, GDK_N,  0 },    0x00D1 },       /* LATIN_CAPITAL_LETTER_N_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_asciitilde, GDK_O,  0 },    0x00D5 },       /* LATIN_CAPITAL_LETTER_O_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_asciitilde, GDK_U,  0 },    0x0168 },       /* LATIN_CAPITAL_LETTER_U_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_asciitilde, GDK_a,  0 },    0x00E3 },       /* LATIN_SMALL_LETTER_A_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_asciitilde, GDK_i,  0 },    0x0129 },       /* LATIN_SMALL_LETTER_I_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_asciitilde, GDK_n,  0 },    0x00F1 },       /* LATIN_SMALL_LETTER_N_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_asciitilde, GDK_o,  0 },    0x00F5 },       /* LATIN_SMALL_LETTER_O_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_asciitilde, GDK_u,  0 },    0x0169 },       /* LATIN_SMALL_LETTER_U_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_diaeresis,  GDK_A,  0 },    0x00C4 },       /* LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_diaeresis,  GDK_E,  0 },    0x00CB },       /* LATIN_CAPITAL_LETTER_E_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_diaeresis,  GDK_I,  0 },    0x00CF },       /* LATIN_CAPITAL_LETTER_I_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_diaeresis,  GDK_O,  0 },    0x00D6 },       /* LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_diaeresis,  GDK_U,  0 },    0x00DC },       /* LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_diaeresis,  GDK_Y,  0 },    0x0178 },       /* LATIN_CAPITAL_LETTER_Y_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_diaeresis,  GDK_a,  0 },    0x00E4 },       /* LATIN_SMALL_LETTER_A_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_diaeresis,  GDK_e,  0 },    0x00EB },       /* LATIN_SMALL_LETTER_E_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_diaeresis,  GDK_i,  0 },    0x00EF },       /* LATIN_SMALL_LETTER_I_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_diaeresis,  GDK_o,  0 },    0x00F6 },       /* LATIN_SMALL_LETTER_O_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_diaeresis,  GDK_u,  0 },    0x00FC },       /* LATIN_SMALL_LETTER_U_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_diaeresis,  GDK_y,  0 },    0x00FF },       /* LATIN_SMALL_LETTER_Y_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_acute,      GDK_A,  0 },    0x00C1 },       /* LATIN_CAPITAL_LETTER_A_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_acute,      GDK_E,  0 },    0x00C9 },       /* LATIN_CAPITAL_LETTER_E_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_acute,      GDK_I,  0 },    0x00CD },       /* LATIN_CAPITAL_LETTER_I_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_acute,      GDK_O,  0 },    0x00D3 },       /* LATIN_CAPITAL_LETTER_O_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_acute,      GDK_U,  0 },    0x00DA },       /* LATIN_CAPITAL_LETTER_U_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_acute,      GDK_Y,  0 },    0x00DD },       /* LATIN_CAPITAL_LETTER_Y_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_acute,      GDK_a,  0 },    0x00E1 },       /* LATIN_SMALL_LETTER_A_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_acute,      GDK_e,  0 },    0x00E9 },       /* LATIN_SMALL_LETTER_E_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_acute,      GDK_i,  0 },    0x00ED },       /* LATIN_SMALL_LETTER_I_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_acute,      GDK_o,  0 },    0x00F3 },       /* LATIN_SMALL_LETTER_O_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_acute,      GDK_u,  0 },    0x00FA },       /* LATIN_SMALL_LETTER_U_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_acute,      GDK_y,  0 },    0x00FD },       /* LATIN_SMALL_LETTER_Y_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_cedilla,    GDK_S,  0 },    0x015E },       /* LATIN_CAPITAL_LETTER_S_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_cedilla,    GDK_s,  0 },    0x015F },       /* LATIN_SMALL_LETTER_S_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_breve,      GDK_G,  0 },    0x011E },       /* LATIN_CAPITAL_LETTER_G_WITH_BREVE */
-  { { GDK_Multi_key,   GDK_breve,      GDK_g,  0 },    0x011F },       /* LATIN_SMALL_LETTER_G_WITH_BREVE */
+static guint16 gtk_compose_seqs[] = {
+  GDK_dead_grave,      GDK_space,      0,      0,      0,      0x0060, /* GRAVE_ACCENT */
+  GDK_dead_grave,      GDK_A,  0,      0,      0,      0x00C0, /* LATIN_CAPITAL_LETTER_A_WITH_GRAVE */
+  GDK_dead_grave,      GDK_E,  0,      0,      0,      0x00C8, /* LATIN_CAPITAL_LETTER_E_WITH_GRAVE */
+  GDK_dead_grave,      GDK_I,  0,      0,      0,      0x00CC, /* LATIN_CAPITAL_LETTER_I_WITH_GRAVE */
+  GDK_dead_grave,      GDK_O,  0,      0,      0,      0x00D2, /* LATIN_CAPITAL_LETTER_O_WITH_GRAVE */
+  GDK_dead_grave,      GDK_U,  0,      0,      0,      0x00D9, /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */
+  GDK_dead_grave,      GDK_a,  0,      0,      0,      0x00E0, /* LATIN_SMALL_LETTER_A_WITH_GRAVE */
+  GDK_dead_grave,      GDK_e,  0,      0,      0,      0x00E8, /* LATIN_SMALL_LETTER_E_WITH_GRAVE */
+  GDK_dead_grave,      GDK_i,  0,      0,      0,      0x00EC, /* LATIN_SMALL_LETTER_I_WITH_GRAVE */
+  GDK_dead_grave,      GDK_o,  0,      0,      0,      0x00F2, /* LATIN_SMALL_LETTER_O_WITH_GRAVE */
+  GDK_dead_grave,      GDK_u,  0,      0,      0,      0x00F9, /* LATIN_SMALL_LETTER_U_WITH_GRAVE */
+  GDK_dead_acute,      GDK_space,      0,      0,      0,      0x0027, /* APOSTROPHE */
+  GDK_dead_acute,      GDK_apostrophe, 0,      0,      0,      0x00B4, /* ACUTE_ACCENT */
+  GDK_dead_acute,      GDK_A,  0,      0,      0,      0x00C1, /* LATIN_CAPITAL_LETTER_A_WITH_ACUTE */
+  GDK_dead_acute,      GDK_E,  0,      0,      0,      0x00C9, /* LATIN_CAPITAL_LETTER_E_WITH_ACUTE */
+  GDK_dead_acute,      GDK_I,  0,      0,      0,      0x00CD, /* LATIN_CAPITAL_LETTER_I_WITH_ACUTE */
+  GDK_dead_acute,      GDK_O,  0,      0,      0,      0x00D3, /* LATIN_CAPITAL_LETTER_O_WITH_ACUTE */
+  GDK_dead_acute,      GDK_U,  0,      0,      0,      0x00DA, /* LATIN_CAPITAL_LETTER_U_WITH_ACUTE */
+  GDK_dead_acute,      GDK_Y,  0,      0,      0,      0x00DD, /* LATIN_CAPITAL_LETTER_Y_WITH_ACUTE */
+  GDK_dead_acute,      GDK_a,  0,      0,      0,      0x00E1, /* LATIN_SMALL_LETTER_A_WITH_ACUTE */
+  GDK_dead_acute,      GDK_e,  0,      0,      0,      0x00E9, /* LATIN_SMALL_LETTER_E_WITH_ACUTE */
+  GDK_dead_acute,      GDK_i,  0,      0,      0,      0x00ED, /* LATIN_SMALL_LETTER_I_WITH_ACUTE */
+  GDK_dead_acute,      GDK_o,  0,      0,      0,      0x00F3, /* LATIN_SMALL_LETTER_O_WITH_ACUTE */
+  GDK_dead_acute,      GDK_u,  0,      0,      0,      0x00FA, /* LATIN_SMALL_LETTER_U_WITH_ACUTE */
+  GDK_dead_acute,      GDK_y,  0,      0,      0,      0x00FD, /* LATIN_SMALL_LETTER_Y_WITH_ACUTE */
+  GDK_dead_acute,      GDK_acute,      0,      0,      0,      0x00B4, /* ACUTE_ACCENT */
+  GDK_dead_acute,      GDK_dead_acute, 0,      0,      0,      0x00B4, /* ACUTE_ACCENT */
+  GDK_dead_circumflex, GDK_space,      0,      0,      0,      0x005E, /* CIRCUMFLEX_ACCENT */
+  GDK_dead_circumflex, GDK_minus,      0,      0,      0,      0x00AF, /* MACRON */
+  GDK_dead_circumflex, GDK_period,     0,      0,      0,      0x00B7, /* MIDDLE_DOT */
+  GDK_dead_circumflex, GDK_slash,      0,      0,      0,      0x007C, /* VERTICAL_LINE */
+  GDK_dead_circumflex, GDK_0,  0,      0,      0,      0x00B0, /* DEGREE_SIGN */
+  GDK_dead_circumflex, GDK_1,  0,      0,      0,      0x00B9, /* SUPERSCRIPT_ONE */
+  GDK_dead_circumflex, GDK_2,  0,      0,      0,      0x00B2, /* SUPERSCRIPT_TWO */
+  GDK_dead_circumflex, GDK_3,  0,      0,      0,      0x00B3, /* SUPERSCRIPT_THREE */
+  GDK_dead_circumflex, GDK_A,  0,      0,      0,      0x00C2, /* LATIN_CAPITAL_LETTER_A_WITH_CIRCUMFLEX */
+  GDK_dead_circumflex, GDK_E,  0,      0,      0,      0x00CA, /* LATIN_CAPITAL_LETTER_E_WITH_CIRCUMFLEX */
+  GDK_dead_circumflex, GDK_I,  0,      0,      0,      0x00CE, /* LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX */
+  GDK_dead_circumflex, GDK_O,  0,      0,      0,      0x00D4, /* LATIN_CAPITAL_LETTER_O_WITH_CIRCUMFLEX */
+  GDK_dead_circumflex, GDK_U,  0,      0,      0,      0x00DB, /* LATIN_CAPITAL_LETTER_U_WITH_CIRCUMFLEX */
+  GDK_dead_circumflex, GDK_underscore, 0,      0,      0,      0x00AF, /* MACRON */
+  GDK_dead_circumflex, GDK_a,  0,      0,      0,      0x00E2, /* LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX */
+  GDK_dead_circumflex, GDK_e,  0,      0,      0,      0x00EA, /* LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX */
+  GDK_dead_circumflex, GDK_i,  0,      0,      0,      0x00EE, /* LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX */
+  GDK_dead_circumflex, GDK_o,  0,      0,      0,      0x00F4, /* LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX */
+  GDK_dead_circumflex, GDK_u,  0,      0,      0,      0x00FB, /* LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX */
+  GDK_dead_tilde,      GDK_space,      0,      0,      0,      0x007E, /* TILDE */
+  GDK_dead_tilde,      GDK_A,  0,      0,      0,      0x00C3, /* LATIN_CAPITAL_LETTER_A_WITH_TILDE */
+  GDK_dead_tilde,      GDK_I,  0,      0,      0,      0x0128, /* LATIN_CAPITAL_LETTER_I_WITH_TILDE */
+  GDK_dead_tilde,      GDK_N,  0,      0,      0,      0x00D1, /* LATIN_CAPITAL_LETTER_N_WITH_TILDE */
+  GDK_dead_tilde,      GDK_O,  0,      0,      0,      0x00D5, /* LATIN_CAPITAL_LETTER_O_WITH_TILDE */
+  GDK_dead_tilde,      GDK_U,  0,      0,      0,      0x0168, /* LATIN_CAPITAL_LETTER_U_WITH_TILDE */
+  GDK_dead_tilde,      GDK_a,  0,      0,      0,      0x00E3, /* LATIN_SMALL_LETTER_A_WITH_TILDE */
+  GDK_dead_tilde,      GDK_i,  0,      0,      0,      0x0129, /* LATIN_SMALL_LETTER_I_WITH_TILDE */
+  GDK_dead_tilde,      GDK_n,  0,      0,      0,      0x00F1, /* LATIN_SMALL_LETTER_N_WITH_TILDE */
+  GDK_dead_tilde,      GDK_o,  0,      0,      0,      0x00F5, /* LATIN_SMALL_LETTER_O_WITH_TILDE */
+  GDK_dead_tilde,      GDK_u,  0,      0,      0,      0x0169, /* LATIN_SMALL_LETTER_U_WITH_TILDE */
+  GDK_dead_tilde,      GDK_asciitilde, 0,      0,      0,      0x007E, /* TILDE */
+  GDK_dead_tilde,      GDK_dead_tilde, 0,      0,      0,      0x007E, /* TILDE */
+  GDK_dead_macron,     GDK_A,  0,      0,      0,      0x0100, /* LATIN_CAPITAL_LETTER_A_WITH_MACRON */
+  GDK_dead_macron,     GDK_E,  0,      0,      0,      0x0112, /* LATIN_CAPITAL_LETTER_E_WITH_MACRON */
+  GDK_dead_macron,     GDK_I,  0,      0,      0,      0x012A, /* LATIN_CAPITAL_LETTER_I_WITH_MACRON */
+  GDK_dead_macron,     GDK_O,  0,      0,      0,      0x014C, /* LATIN_CAPITAL_LETTER_O_WITH_MACRON */
+  GDK_dead_macron,     GDK_U,  0,      0,      0,      0x00D9, /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */
+  GDK_dead_macron,     GDK_a,  0,      0,      0,      0x0101, /* LATIN_SMALL_LETTER_A_WITH_MACRON */
+  GDK_dead_macron,     GDK_e,  0,      0,      0,      0x0113, /* LATIN_SMALL_LETTER_E_WITH_MACRON */
+  GDK_dead_macron,     GDK_i,  0,      0,      0,      0x012B, /* LATIN_SMALL_LETTER_I_WITH_MACRON */
+  GDK_dead_macron,     GDK_o,  0,      0,      0,      0x014D, /* LATIN_SMALL_LETTER_O_WITH_MACRON */
+  GDK_dead_macron,     GDK_u,  0,      0,      0,      0x016B, /* LATIN_SMALL_LETTER_U_WITH_MACRON */
+  GDK_dead_macron,     GDK_macron,     0,      0,      0,      0x00AF, /* MACRON */
+  GDK_dead_macron,     GDK_dead_macron,        0,      0,      0,      0x00AF, /* MACRON */
+  GDK_dead_breve,      GDK_G,  0,      0,      0,      0x011E, /* LATIN_CAPITAL_LETTER_G_WITH_BREVE */
+  GDK_dead_breve,      GDK_g,  0,      0,      0,      0x011F, /* LATIN_SMALL_LETTER_G_WITH_BREVE */
+  GDK_dead_abovedot,   GDK_E,  0,      0,      0,      0x0116, /* LATIN_CAPITAL_LETTER_E_WITH_DOT_ABOVE */
+  GDK_dead_abovedot,   GDK_I,  0,      0,      0,      0x0130, /* LATIN_CAPITAL_LETTER_I_WITH_DOT_ABOVE */
+  GDK_dead_abovedot,   GDK_e,  0,      0,      0,      0x0117, /* LATIN_SMALL_LETTER_E_WITH_DOT_ABOVE */
+  GDK_dead_abovedot,   GDK_i,  0,      0,      0,      0x0131, /* LATIN_SMALL_LETTER_DOTLESS_I */
+  GDK_dead_abovedot,   GDK_abovedot,   0,      0,      0,      0x02D9, /* DOT_ABOVE */
+  GDK_dead_abovedot,   GDK_dead_abovedot,      0,      0,      0,      0x02D9, /* DOT_ABOVE */
+  GDK_dead_diaeresis,  GDK_space,      0,      0,      0,      0x00A8, /* DIAERESIS */
+  GDK_dead_diaeresis,  GDK_quotedbl,   0,      0,      0,      0x00A8, /* DIAERESIS */
+  GDK_dead_diaeresis,  GDK_A,  0,      0,      0,      0x00C4, /* LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS */
+  GDK_dead_diaeresis,  GDK_E,  0,      0,      0,      0x00CB, /* LATIN_CAPITAL_LETTER_E_WITH_DIAERESIS */
+  GDK_dead_diaeresis,  GDK_I,  0,      0,      0,      0x00CF, /* LATIN_CAPITAL_LETTER_I_WITH_DIAERESIS */
+  GDK_dead_diaeresis,  GDK_O,  0,      0,      0,      0x00D6, /* LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS */
+  GDK_dead_diaeresis,  GDK_U,  0,      0,      0,      0x00DC, /* LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS */
+  GDK_dead_diaeresis,  GDK_Y,  0,      0,      0,      0x0178, /* LATIN_CAPITAL_LETTER_Y_WITH_DIAERESIS */
+  GDK_dead_diaeresis,  GDK_a,  0,      0,      0,      0x00E4, /* LATIN_SMALL_LETTER_A_WITH_DIAERESIS */
+  GDK_dead_diaeresis,  GDK_e,  0,      0,      0,      0x00EB, /* LATIN_SMALL_LETTER_E_WITH_DIAERESIS */
+  GDK_dead_diaeresis,  GDK_i,  0,      0,      0,      0x00EF, /* LATIN_SMALL_LETTER_I_WITH_DIAERESIS */
+  GDK_dead_diaeresis,  GDK_o,  0,      0,      0,      0x00F6, /* LATIN_SMALL_LETTER_O_WITH_DIAERESIS */
+  GDK_dead_diaeresis,  GDK_u,  0,      0,      0,      0x00FC, /* LATIN_SMALL_LETTER_U_WITH_DIAERESIS */
+  GDK_dead_diaeresis,  GDK_y,  0,      0,      0,      0x00FF, /* LATIN_SMALL_LETTER_Y_WITH_DIAERESIS */
+  GDK_dead_diaeresis,  GDK_diaeresis,  0,      0,      0,      0x00A8, /* DIAERESIS */
+  GDK_dead_diaeresis,  GDK_dead_diaeresis,     0,      0,      0,      0x00A8, /* DIAERESIS */
+  GDK_dead_abovering,  GDK_A,  0,      0,      0,      0x00C5, /* LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE */
+  GDK_dead_abovering,  GDK_a,  0,      0,      0,      0x00E5, /* LATIN_SMALL_LETTER_A_WITH_RING_ABOVE */
+  GDK_dead_abovering,  GDK_dead_abovering,     0,      0,      0,      0x02DA, /* RING_ABOVE */
+  GDK_dead_caron,      GDK_C,  0,      0,      0,      0x010C, /* LATIN_CAPITAL_LETTER_C_WITH_CARON */
+  GDK_dead_caron,      GDK_S,  0,      0,      0,      0x0160, /* LATIN_CAPITAL_LETTER_S_WITH_CARON */
+  GDK_dead_caron,      GDK_Z,  0,      0,      0,      0x017D, /* LATIN_CAPITAL_LETTER_Z_WITH_CARON */
+  GDK_dead_caron,      GDK_c,  0,      0,      0,      0x010D, /* LATIN_SMALL_LETTER_C_WITH_CARON */
+  GDK_dead_caron,      GDK_s,  0,      0,      0,      0x0161, /* LATIN_SMALL_LETTER_S_WITH_CARON */
+  GDK_dead_caron,      GDK_z,  0,      0,      0,      0x017E, /* LATIN_SMALL_LETTER_Z_WITH_CARON */
+  GDK_dead_caron,      GDK_caron,      0,      0,      0,      0x02C7, /* CARON */
+  GDK_dead_caron,      GDK_dead_caron, 0,      0,      0,      0x02C7, /* CARON */
+  GDK_dead_cedilla,    GDK_comma,      0,      0,      0,      0x00B8, /* CEDILLA */
+  GDK_dead_cedilla,    GDK_minus,      0,      0,      0,      0x00AC, /* NOT_SIGN */
+  GDK_dead_cedilla,    GDK_C,  0,      0,      0,      0x00C7, /* LATIN_CAPITAL_LETTER_C_WITH_CEDILLA */
+  GDK_dead_cedilla,    GDK_G,  0,      0,      0,      0x0122, /* LATIN_CAPITAL_LETTER_G_WITH_CEDILLA */
+  GDK_dead_cedilla,    GDK_K,  0,      0,      0,      0x0136, /* LATIN_CAPITAL_LETTER_K_WITH_CEDILLA */
+  GDK_dead_cedilla,    GDK_L,  0,      0,      0,      0x013B, /* LATIN_CAPITAL_LETTER_L_WITH_CEDILLA */
+  GDK_dead_cedilla,    GDK_N,  0,      0,      0,      0x0145, /* LATIN_CAPITAL_LETTER_N_WITH_CEDILLA */
+  GDK_dead_cedilla,    GDK_R,  0,      0,      0,      0x0156, /* LATIN_CAPITAL_LETTER_R_WITH_CEDILLA */
+  GDK_dead_cedilla,    GDK_S,  0,      0,      0,      0x015E, /* LATIN_CAPITAL_LETTER_S_WITH_CEDILLA */
+  GDK_dead_cedilla,    GDK_c,  0,      0,      0,      0x00E7, /* LATIN_SMALL_LETTER_C_WITH_CEDILLA */
+  GDK_dead_cedilla,    GDK_g,  0,      0,      0,      0x0123, /* LATIN_SMALL_LETTER_G_WITH_CEDILLA */
+  GDK_dead_cedilla,    GDK_k,  0,      0,      0,      0x0137, /* LATIN_SMALL_LETTER_K_WITH_CEDILLA */
+  GDK_dead_cedilla,    GDK_l,  0,      0,      0,      0x013C, /* LATIN_SMALL_LETTER_L_WITH_CEDILLA */
+  GDK_dead_cedilla,    GDK_n,  0,      0,      0,      0x0146, /* LATIN_SMALL_LETTER_N_WITH_CEDILLA */
+  GDK_dead_cedilla,    GDK_r,  0,      0,      0,      0x0157, /* LATIN_SMALL_LETTER_R_WITH_CEDILLA */
+  GDK_dead_cedilla,    GDK_s,  0,      0,      0,      0x015F, /* LATIN_SMALL_LETTER_S_WITH_CEDILLA */
+  GDK_dead_cedilla,    GDK_cedilla,    0,      0,      0,      0x00B8, /* CEDILLA */
+  GDK_dead_cedilla,    GDK_dead_cedilla,       0,      0,      0,      0x00B8, /* CEDILLA */
+  GDK_dead_ogonek,     GDK_A,  0,      0,      0,      0x0104, /* LATIN_CAPITAL_LETTER_A_WITH_OGONEK */
+  GDK_dead_ogonek,     GDK_E,  0,      0,      0,      0x0118, /* LATIN_CAPITAL_LETTER_E_WITH_OGONEK */
+  GDK_dead_ogonek,     GDK_I,  0,      0,      0,      0x012E, /* LATIN_CAPITAL_LETTER_I_WITH_OGONEK */
+  GDK_dead_ogonek,     GDK_U,  0,      0,      0,      0x0172, /* LATIN_CAPITAL_LETTER_U_WITH_OGONEK */
+  GDK_dead_ogonek,     GDK_a,  0,      0,      0,      0x0105, /* LATIN_SMALL_LETTER_A_WITH_OGONEK */
+  GDK_dead_ogonek,     GDK_e,  0,      0,      0,      0x0119, /* LATIN_SMALL_LETTER_E_WITH_OGONEK */
+  GDK_dead_ogonek,     GDK_i,  0,      0,      0,      0x012F, /* LATIN_SMALL_LETTER_I_WITH_OGONEK */
+  GDK_dead_ogonek,     GDK_u,  0,      0,      0,      0x0173, /* LATIN_SMALL_LETTER_U_WITH_OGONEK */
+  GDK_dead_ogonek,     GDK_ogonek,     0,      0,      0,      0x02DB, /* OGONEK */
+  GDK_dead_ogonek,     GDK_dead_ogonek,        0,      0,      0,      0x02DB, /* OGONEK */
+  GDK_Multi_key,       GDK_space,      GDK_space,      0,      0,      0x00A0, /* NOxBREAK_SPACE */
+  GDK_Multi_key,       GDK_space,      GDK_apostrophe, 0,      0,      0x0027, /* APOSTROPHE */
+  GDK_Multi_key,       GDK_space,      GDK_minus,      0,      0,      0x007E, /* TILDE */
+  GDK_Multi_key,       GDK_space,      GDK_greater,    0,      0,      0x005E, /* CIRCUMFLEX_ACCENT */
+  GDK_Multi_key,       GDK_space,      GDK_asciicircum,        0,      0,      0x005E, /* CIRCUMFLEX_ACCENT */
+  GDK_Multi_key,       GDK_space,      GDK_grave,      0,      0,      0x0060, /* GRAVE_ACCENT */
+  GDK_Multi_key,       GDK_space,      GDK_asciitilde, 0,      0,      0x007E, /* TILDE */
+  GDK_Multi_key,       GDK_exclam,     GDK_exclam,     0,      0,      0x00A1, /* INVERTED_EXCLAMATION_MARK */
+  GDK_Multi_key,       GDK_exclam,     GDK_P,  0,      0,      0x00B6, /* PILCROW_SIGN */
+  GDK_Multi_key,       GDK_exclam,     GDK_S,  0,      0,      0x00A7, /* SECTION_SIGN */
+  GDK_Multi_key,       GDK_exclam,     GDK_p,  0,      0,      0x00B6, /* PILCROW_SIGN */
+  GDK_Multi_key,       GDK_exclam,     GDK_s,  0,      0,      0x00A7, /* SECTION_SIGN */
+  GDK_Multi_key,       GDK_quotedbl,   GDK_quotedbl,   0,      0,      0x00A8, /* DIAERESIS */
+  GDK_Multi_key,       GDK_quotedbl,   GDK_A,  0,      0,      0x00C4, /* LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_quotedbl,   GDK_E,  0,      0,      0x00CB, /* LATIN_CAPITAL_LETTER_E_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_quotedbl,   GDK_I,  0,      0,      0x00CF, /* LATIN_CAPITAL_LETTER_I_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_quotedbl,   GDK_O,  0,      0,      0x00D6, /* LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_quotedbl,   GDK_U,  0,      0,      0x00DC, /* LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_quotedbl,   GDK_Y,  0,      0,      0x0178, /* LATIN_CAPITAL_LETTER_Y_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_quotedbl,   GDK_a,  0,      0,      0x00E4, /* LATIN_SMALL_LETTER_A_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_quotedbl,   GDK_e,  0,      0,      0x00EB, /* LATIN_SMALL_LETTER_E_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_quotedbl,   GDK_i,  0,      0,      0x00EF, /* LATIN_SMALL_LETTER_I_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_quotedbl,   GDK_o,  0,      0,      0x00F6, /* LATIN_SMALL_LETTER_O_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_quotedbl,   GDK_u,  0,      0,      0x00FC, /* LATIN_SMALL_LETTER_U_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_quotedbl,   GDK_y,  0,      0,      0x00FF, /* LATIN_SMALL_LETTER_Y_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_apostrophe, GDK_space,      0,      0,      0x0027, /* APOSTROPHE */
+  GDK_Multi_key,       GDK_apostrophe, GDK_apostrophe, 0,      0,      0x00B4, /* ACUTE_ACCENT */
+  GDK_Multi_key,       GDK_apostrophe, GDK_A,  0,      0,      0x00C1, /* LATIN_CAPITAL_LETTER_A_WITH_ACUTE */
+  GDK_Multi_key,       GDK_apostrophe, GDK_E,  0,      0,      0x00C9, /* LATIN_CAPITAL_LETTER_E_WITH_ACUTE */
+  GDK_Multi_key,       GDK_apostrophe, GDK_I,  0,      0,      0x00CD, /* LATIN_CAPITAL_LETTER_I_WITH_ACUTE */
+  GDK_Multi_key,       GDK_apostrophe, GDK_O,  0,      0,      0x00D3, /* LATIN_CAPITAL_LETTER_O_WITH_ACUTE */
+  GDK_Multi_key,       GDK_apostrophe, GDK_U,  0,      0,      0x00DA, /* LATIN_CAPITAL_LETTER_U_WITH_ACUTE */
+  GDK_Multi_key,       GDK_apostrophe, GDK_Y,  0,      0,      0x00DD, /* LATIN_CAPITAL_LETTER_Y_WITH_ACUTE */
+  GDK_Multi_key,       GDK_apostrophe, GDK_a,  0,      0,      0x00E1, /* LATIN_SMALL_LETTER_A_WITH_ACUTE */
+  GDK_Multi_key,       GDK_apostrophe, GDK_e,  0,      0,      0x00E9, /* LATIN_SMALL_LETTER_E_WITH_ACUTE */
+  GDK_Multi_key,       GDK_apostrophe, GDK_i,  0,      0,      0x00ED, /* LATIN_SMALL_LETTER_I_WITH_ACUTE */
+  GDK_Multi_key,       GDK_apostrophe, GDK_o,  0,      0,      0x00F3, /* LATIN_SMALL_LETTER_O_WITH_ACUTE */
+  GDK_Multi_key,       GDK_apostrophe, GDK_u,  0,      0,      0x00FA, /* LATIN_SMALL_LETTER_U_WITH_ACUTE */
+  GDK_Multi_key,       GDK_apostrophe, GDK_y,  0,      0,      0x00FD, /* LATIN_SMALL_LETTER_Y_WITH_ACUTE */
+  GDK_Multi_key,       GDK_parenleft,  GDK_parenleft,  0,      0,      0x005B, /* LEFT_SQUARE_BRACKET */
+  GDK_Multi_key,       GDK_parenleft,  GDK_minus,      0,      0,      0x007B, /* LEFT_CURLY_BRACKET */
+  GDK_Multi_key,       GDK_parenleft,  GDK_G,  0,      0,      0x011E, /* LATIN_CAPITAL_LETTER_G_WITH_BREVE */
+  GDK_Multi_key,       GDK_parenleft,  GDK_c,  0,      0,      0x00A9, /* COPYRIGHT_SIGN */
+  GDK_Multi_key,       GDK_parenleft,  GDK_g,  0,      0,      0x011F, /* LATIN_SMALL_LETTER_G_WITH_BREVE */
+  GDK_Multi_key,       GDK_parenleft,  GDK_r,  0,      0,      0x00AE, /* REGISTERED_SIGN */
+  GDK_Multi_key,       GDK_parenright, GDK_parenright, 0,      0,      0x005D, /* RIGHT_SQUARE_BRACKET */
+  GDK_Multi_key,       GDK_parenright, GDK_minus,      0,      0,      0x007D, /* RIGHT_CURLY_BRACKET */
+  GDK_Multi_key,       GDK_asterisk,   GDK_0,  0,      0,      0x00B0, /* DEGREE_SIGN */
+  GDK_Multi_key,       GDK_asterisk,   GDK_A,  0,      0,      0x00C5, /* LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE */
+  GDK_Multi_key,       GDK_asterisk,   GDK_a,  0,      0,      0x00E5, /* LATIN_SMALL_LETTER_A_WITH_RING_ABOVE */
+  GDK_Multi_key,       GDK_plus,       GDK_plus,       0,      0,      0x0023, /* NUMBER_SIGN */
+  GDK_Multi_key,       GDK_plus,       GDK_minus,      0,      0,      0x00B1, /* PLUSxMINUS_SIGN */
+  GDK_Multi_key,       GDK_comma,      GDK_comma,      0,      0,      0x00B8, /* CEDILLA */
+  GDK_Multi_key,       GDK_comma,      GDK_minus,      0,      0,      0x00AC, /* NOT_SIGN */
+  GDK_Multi_key,       GDK_comma,      GDK_A,  0,      0,      0x0104, /* LATIN_CAPITAL_LETTER_A_WITH_OGONEK */
+  GDK_Multi_key,       GDK_comma,      GDK_C,  0,      0,      0x00C7, /* LATIN_CAPITAL_LETTER_C_WITH_CEDILLA */
+  GDK_Multi_key,       GDK_comma,      GDK_E,  0,      0,      0x0118, /* LATIN_CAPITAL_LETTER_E_WITH_OGONEK */
+  GDK_Multi_key,       GDK_comma,      GDK_G,  0,      0,      0x0122, /* LATIN_CAPITAL_LETTER_G_WITH_CEDILLA */
+  GDK_Multi_key,       GDK_comma,      GDK_I,  0,      0,      0x012E, /* LATIN_CAPITAL_LETTER_I_WITH_OGONEK */
+  GDK_Multi_key,       GDK_comma,      GDK_K,  0,      0,      0x0136, /* LATIN_CAPITAL_LETTER_K_WITH_CEDILLA */
+  GDK_Multi_key,       GDK_comma,      GDK_L,  0,      0,      0x013B, /* LATIN_CAPITAL_LETTER_L_WITH_CEDILLA */
+  GDK_Multi_key,       GDK_comma,      GDK_N,  0,      0,      0x0145, /* LATIN_CAPITAL_LETTER_N_WITH_CEDILLA */
+  GDK_Multi_key,       GDK_comma,      GDK_R,  0,      0,      0x0156, /* LATIN_CAPITAL_LETTER_R_WITH_CEDILLA */
+  GDK_Multi_key,       GDK_comma,      GDK_S,  0,      0,      0x015E, /* LATIN_CAPITAL_LETTER_S_WITH_CEDILLA */
+  GDK_Multi_key,       GDK_comma,      GDK_U,  0,      0,      0x0172, /* LATIN_CAPITAL_LETTER_U_WITH_OGONEK */
+  GDK_Multi_key,       GDK_comma,      GDK_a,  0,      0,      0x0105, /* LATIN_SMALL_LETTER_A_WITH_OGONEK */
+  GDK_Multi_key,       GDK_comma,      GDK_c,  0,      0,      0x00E7, /* LATIN_SMALL_LETTER_C_WITH_CEDILLA */
+  GDK_Multi_key,       GDK_comma,      GDK_e,  0,      0,      0x0119, /* LATIN_SMALL_LETTER_E_WITH_OGONEK */
+  GDK_Multi_key,       GDK_comma,      GDK_g,  0,      0,      0x0123, /* LATIN_SMALL_LETTER_G_WITH_CEDILLA */
+  GDK_Multi_key,       GDK_comma,      GDK_i,  0,      0,      0x012F, /* LATIN_SMALL_LETTER_I_WITH_OGONEK */
+  GDK_Multi_key,       GDK_comma,      GDK_k,  0,      0,      0x0137, /* LATIN_SMALL_LETTER_K_WITH_CEDILLA */
+  GDK_Multi_key,       GDK_comma,      GDK_l,  0,      0,      0x013C, /* LATIN_SMALL_LETTER_L_WITH_CEDILLA */
+  GDK_Multi_key,       GDK_comma,      GDK_n,  0,      0,      0x0146, /* LATIN_SMALL_LETTER_N_WITH_CEDILLA */
+  GDK_Multi_key,       GDK_comma,      GDK_r,  0,      0,      0x0157, /* LATIN_SMALL_LETTER_R_WITH_CEDILLA */
+  GDK_Multi_key,       GDK_comma,      GDK_s,  0,      0,      0x015F, /* LATIN_SMALL_LETTER_S_WITH_CEDILLA */
+  GDK_Multi_key,       GDK_comma,      GDK_u,  0,      0,      0x0173, /* LATIN_SMALL_LETTER_U_WITH_OGONEK */
+  GDK_Multi_key,       GDK_minus,      GDK_space,      0,      0,      0x007E, /* TILDE */
+  GDK_Multi_key,       GDK_minus,      GDK_parenleft,  0,      0,      0x007B, /* LEFT_CURLY_BRACKET */
+  GDK_Multi_key,       GDK_minus,      GDK_parenright, 0,      0,      0x007D, /* RIGHT_CURLY_BRACKET */
+  GDK_Multi_key,       GDK_minus,      GDK_plus,       0,      0,      0x00B1, /* PLUSxMINUS_SIGN */
+  GDK_Multi_key,       GDK_minus,      GDK_comma,      0,      0,      0x00AC, /* NOT_SIGN */
+  GDK_Multi_key,       GDK_minus,      GDK_minus,      0,      0,      0x00AD, /* SOFT_HYPHEN */
+  GDK_Multi_key,       GDK_minus,      GDK_colon,      0,      0,      0x00F7, /* DIVISION_SIGN */
+  GDK_Multi_key,       GDK_minus,      GDK_A,  0,      0,      0x00C3, /* LATIN_CAPITAL_LETTER_A_WITH_TILDE */
+  GDK_Multi_key,       GDK_minus,      GDK_D,  0,      0,      0x0110, /* LATIN_CAPITAL_LETTER_D_WITH_STROKE */
+  GDK_Multi_key,       GDK_minus,      GDK_E,  0,      0,      0x0112, /* LATIN_CAPITAL_LETTER_E_WITH_MACRON */
+  GDK_Multi_key,       GDK_minus,      GDK_I,  0,      0,      0x012A, /* LATIN_CAPITAL_LETTER_I_WITH_MACRON */
+  GDK_Multi_key,       GDK_minus,      GDK_L,  0,      0,      0x00A3, /* POUND_SIGN */
+  GDK_Multi_key,       GDK_minus,      GDK_N,  0,      0,      0x00D1, /* LATIN_CAPITAL_LETTER_N_WITH_TILDE */
+  GDK_Multi_key,       GDK_minus,      GDK_O,  0,      0,      0x00D5, /* LATIN_CAPITAL_LETTER_O_WITH_TILDE */
+  GDK_Multi_key,       GDK_minus,      GDK_U,  0,      0,      0x00D9, /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */
+  GDK_Multi_key,       GDK_minus,      GDK_Y,  0,      0,      0x00A5, /* YEN_SIGN */
+  GDK_Multi_key,       GDK_minus,      GDK_asciicircum,        0,      0,      0x00AF, /* MACRON */
+  GDK_Multi_key,       GDK_minus,      GDK_a,  0,      0,      0x00E3, /* LATIN_SMALL_LETTER_A_WITH_TILDE */
+  GDK_Multi_key,       GDK_minus,      GDK_d,  0,      0,      0x0111, /* LATIN_SMALL_LETTER_D_WITH_STROKE */
+  GDK_Multi_key,       GDK_minus,      GDK_e,  0,      0,      0x0113, /* LATIN_SMALL_LETTER_E_WITH_MACRON */
+  GDK_Multi_key,       GDK_minus,      GDK_i,  0,      0,      0x012B, /* LATIN_SMALL_LETTER_I_WITH_MACRON */
+  GDK_Multi_key,       GDK_minus,      GDK_l,  0,      0,      0x00A3, /* POUND_SIGN */
+  GDK_Multi_key,       GDK_minus,      GDK_n,  0,      0,      0x00F1, /* LATIN_SMALL_LETTER_N_WITH_TILDE */
+  GDK_Multi_key,       GDK_minus,      GDK_o,  0,      0,      0x00F5, /* LATIN_SMALL_LETTER_O_WITH_TILDE */
+  GDK_Multi_key,       GDK_minus,      GDK_u,  0,      0,      0x016B, /* LATIN_SMALL_LETTER_U_WITH_MACRON */
+  GDK_Multi_key,       GDK_minus,      GDK_y,  0,      0,      0x00A5, /* YEN_SIGN */
+  GDK_Multi_key,       GDK_period,     GDK_period,     0,      0,      0x02D9, /* DOT_ABOVE */
+  GDK_Multi_key,       GDK_period,     GDK_B,  0,      0,      0x1E02, /* LATIN_CAPITAL_LETTER_B_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_period,     GDK_C,  0,      0,      0x010A, /* LATIN_CAPITAL_LETTER_C_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_period,     GDK_D,  0,      0,      0x1E0A, /* LATIN_CAPITAL_LETTER_D_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_period,     GDK_E,  0,      0,      0x0116, /* LATIN_CAPITAL_LETTER_E_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_period,     GDK_F,  0,      0,      0x1E1E, /* LATIN_CAPITAL_LETTER_F_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_period,     GDK_G,  0,      0,      0x0120, /* LATIN_CAPITAL_LETTER_G_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_period,     GDK_I,  0,      0,      0x0130, /* LATIN_CAPITAL_LETTER_I_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_period,     GDK_M,  0,      0,      0x1E40, /* LATIN_CAPITAL_LETTER_M_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_period,     GDK_P,  0,      0,      0x1E56, /* LATIN_CAPITAL_LETTER_P_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_period,     GDK_S,  0,      0,      0x1E60, /* LATIN_CAPITAL_LETTER_S_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_period,     GDK_T,  0,      0,      0x1E6A, /* LATIN_CAPITAL_LETTER_T_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_period,     GDK_asciicircum,        0,      0,      0x00B7, /* MIDDLE_DOT */
+  GDK_Multi_key,       GDK_period,     GDK_b,  0,      0,      0x1E03, /* LATIN_SMALL_LETTER_B_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_period,     GDK_c,  0,      0,      0x010B, /* LATIN_SMALL_LETTER_C_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_period,     GDK_d,  0,      0,      0x1E0B, /* LATIN_SMALL_LETTER_D_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_period,     GDK_e,  0,      0,      0x0117, /* LATIN_SMALL_LETTER_E_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_period,     GDK_f,  0,      0,      0x1E1F, /* LATIN_SMALL_LETTER_F_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_period,     GDK_g,  0,      0,      0x0121, /* LATIN_SMALL_LETTER_G_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_period,     GDK_i,  0,      0,      0x0131, /* LATIN_SMALL_LETTER_DOTLESS_I */
+  GDK_Multi_key,       GDK_period,     GDK_m,  0,      0,      0x1E41, /* LATIN_SMALL_LETTER_M_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_period,     GDK_p,  0,      0,      0x1E57, /* LATIN_SMALL_LETTER_P_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_period,     GDK_s,  0,      0,      0x1E61, /* LATIN_SMALL_LETTER_S_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_period,     GDK_t,  0,      0,      0x1E6B, /* LATIN_SMALL_LETTER_T_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_slash,      GDK_slash,      0,      0,      0x005C, /* REVERSE_SOLIDUS */
+  GDK_Multi_key,       GDK_slash,      GDK_less,       0,      0,      0x005C, /* REVERSE_SOLIDUS */
+  GDK_Multi_key,       GDK_slash,      GDK_C,  0,      0,      0x00A2, /* CENT_SIGN */
+  GDK_Multi_key,       GDK_slash,      GDK_O,  0,      0,      0x00D8, /* LATIN_CAPITAL_LETTER_O_WITH_STROKE */
+  GDK_Multi_key,       GDK_slash,      GDK_T,  0,      0,      0x0166, /* LATIN_CAPITAL_LETTER_T_WITH_STROKE */
+  GDK_Multi_key,       GDK_slash,      GDK_U,  0,      0,      0x00B5, /* MICRO_SIGN */
+  GDK_Multi_key,       GDK_slash,      GDK_asciicircum,        0,      0,      0x007C, /* VERTICAL_LINE */
+  GDK_Multi_key,       GDK_slash,      GDK_c,  0,      0,      0x00A2, /* CENT_SIGN */
+  GDK_Multi_key,       GDK_slash,      GDK_o,  0,      0,      0x00F8, /* LATIN_SMALL_LETTER_O_WITH_STROKE */
+  GDK_Multi_key,       GDK_slash,      GDK_t,  0,      0,      0x0167, /* LATIN_SMALL_LETTER_T_WITH_STROKE */
+  GDK_Multi_key,       GDK_slash,      GDK_u,  0,      0,      0x00B5, /* MICRO_SIGN */
+  GDK_Multi_key,       GDK_0,  GDK_asterisk,   0,      0,      0x00B0, /* DEGREE_SIGN */
+  GDK_Multi_key,       GDK_0,  GDK_C,  0,      0,      0x00A9, /* COPYRIGHT_SIGN */
+  GDK_Multi_key,       GDK_0,  GDK_S,  0,      0,      0x00A7, /* SECTION_SIGN */
+  GDK_Multi_key,       GDK_0,  GDK_X,  0,      0,      0x00A4, /* CURRENCY_SIGN */
+  GDK_Multi_key,       GDK_0,  GDK_asciicircum,        0,      0,      0x00B0, /* DEGREE_SIGN */
+  GDK_Multi_key,       GDK_0,  GDK_c,  0,      0,      0x00A9, /* COPYRIGHT_SIGN */
+  GDK_Multi_key,       GDK_0,  GDK_s,  0,      0,      0x00A7, /* SECTION_SIGN */
+  GDK_Multi_key,       GDK_0,  GDK_x,  0,      0,      0x00A4, /* CURRENCY_SIGN */
+  GDK_Multi_key,       GDK_1,  GDK_S,  0,      0,      0x00B9, /* SUPERSCRIPT_ONE */
+  GDK_Multi_key,       GDK_1,  GDK_asciicircum,        0,      0,      0x00B9, /* SUPERSCRIPT_ONE */
+  GDK_Multi_key,       GDK_1,  GDK_s,  0,      0,      0x00B9, /* SUPERSCRIPT_ONE */
+  GDK_Multi_key,       GDK_2,  GDK_S,  0,      0,      0x00B2, /* SUPERSCRIPT_TWO */
+  GDK_Multi_key,       GDK_2,  GDK_asciicircum,        0,      0,      0x00B2, /* SUPERSCRIPT_TWO */
+  GDK_Multi_key,       GDK_2,  GDK_s,  0,      0,      0x00B2, /* SUPERSCRIPT_TWO */
+  GDK_Multi_key,       GDK_3,  GDK_S,  0,      0,      0x00B3, /* SUPERSCRIPT_THREE */
+  GDK_Multi_key,       GDK_3,  GDK_asciicircum,        0,      0,      0x00B3, /* SUPERSCRIPT_THREE */
+  GDK_Multi_key,       GDK_3,  GDK_s,  0,      0,      0x00B3, /* SUPERSCRIPT_THREE */
+  GDK_Multi_key,       GDK_colon,      GDK_minus,      0,      0,      0x00F7, /* DIVISION_SIGN */
+  GDK_Multi_key,       GDK_less,       GDK_slash,      0,      0,      0x005C, /* REVERSE_SOLIDUS */
+  GDK_Multi_key,       GDK_less,       GDK_less,       0,      0,      0x00AB, /* LEFTxPOINTING_DOUBLE_ANGLE_QUOTATION_MARK */
+  GDK_Multi_key,       GDK_less,       GDK_C,  0,      0,      0x010C, /* LATIN_CAPITAL_LETTER_C_WITH_CARON */
+  GDK_Multi_key,       GDK_less,       GDK_S,  0,      0,      0x0160, /* LATIN_CAPITAL_LETTER_S_WITH_CARON */
+  GDK_Multi_key,       GDK_less,       GDK_Z,  0,      0,      0x017D, /* LATIN_CAPITAL_LETTER_Z_WITH_CARON */
+  GDK_Multi_key,       GDK_less,       GDK_c,  0,      0,      0x010D, /* LATIN_SMALL_LETTER_C_WITH_CARON */
+  GDK_Multi_key,       GDK_less,       GDK_s,  0,      0,      0x0161, /* LATIN_SMALL_LETTER_S_WITH_CARON */
+  GDK_Multi_key,       GDK_less,       GDK_z,  0,      0,      0x017E, /* LATIN_SMALL_LETTER_Z_WITH_CARON */
+  GDK_Multi_key,       GDK_equal,      GDK_C,  0,      0,      0x20AC, /* EURO_SIGN */
+  GDK_Multi_key,       GDK_equal,      GDK_L,  0,      0,      0x00A3, /* POUND_SIGN */
+  GDK_Multi_key,       GDK_equal,      GDK_Y,  0,      0,      0x00A5, /* YEN_SIGN */
+  GDK_Multi_key,       GDK_equal,      GDK_e,  0,      0,      0x20AC, /* EURO_SIGN */
+  GDK_Multi_key,       GDK_equal,      GDK_l,  0,      0,      0x00A3, /* POUND_SIGN */
+  GDK_Multi_key,       GDK_equal,      GDK_y,  0,      0,      0x00A5, /* YEN_SIGN */
+  GDK_Multi_key,       GDK_greater,    GDK_space,      0,      0,      0x005E, /* CIRCUMFLEX_ACCENT */
+  GDK_Multi_key,       GDK_greater,    GDK_greater,    0,      0,      0x00BB, /* RIGHTxPOINTING_DOUBLE_ANGLE_QUOTATION_MARK */
+  GDK_Multi_key,       GDK_greater,    GDK_A,  0,      0,      0x00C2, /* LATIN_CAPITAL_LETTER_A_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_greater,    GDK_E,  0,      0,      0x00CA, /* LATIN_CAPITAL_LETTER_E_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_greater,    GDK_I,  0,      0,      0x00CE, /* LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_greater,    GDK_O,  0,      0,      0x00D4, /* LATIN_CAPITAL_LETTER_O_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_greater,    GDK_U,  0,      0,      0x00DB, /* LATIN_CAPITAL_LETTER_U_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_greater,    GDK_a,  0,      0,      0x00E2, /* LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_greater,    GDK_e,  0,      0,      0x00EA, /* LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_greater,    GDK_i,  0,      0,      0x00EE, /* LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_greater,    GDK_o,  0,      0,      0x00F4, /* LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_greater,    GDK_u,  0,      0,      0x00FB, /* LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_question,   GDK_question,   0,      0,      0x00BF, /* INVERTED_QUESTION_MARK */
+  GDK_Multi_key,       GDK_A,  GDK_quotedbl,   0,      0,      0x00C4, /* LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_A,  GDK_apostrophe, 0,      0,      0x00C1, /* LATIN_CAPITAL_LETTER_A_WITH_ACUTE */
+  GDK_Multi_key,       GDK_A,  GDK_asterisk,   0,      0,      0x00C5, /* LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE */
+  GDK_Multi_key,       GDK_A,  GDK_comma,      0,      0,      0x0104, /* LATIN_CAPITAL_LETTER_A_WITH_OGONEK */
+  GDK_Multi_key,       GDK_A,  GDK_minus,      0,      0,      0x00C3, /* LATIN_CAPITAL_LETTER_A_WITH_TILDE */
+  GDK_Multi_key,       GDK_A,  GDK_greater,    0,      0,      0x00C2, /* LATIN_CAPITAL_LETTER_A_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_A,  GDK_A,  0,      0,      0x00C5, /* LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE */
+  GDK_Multi_key,       GDK_A,  GDK_E,  0,      0,      0x00C6, /* LATIN_CAPITAL_LETTER_AE */
+  GDK_Multi_key,       GDK_A,  GDK_asciicircum,        0,      0,      0x00C2, /* LATIN_CAPITAL_LETTER_A_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_A,  GDK_underscore, 0,      0,      0x00AA, /* FEMININE_ORDINAL_INDICATOR */
+  GDK_Multi_key,       GDK_A,  GDK_grave,      0,      0,      0x00C0, /* LATIN_CAPITAL_LETTER_A_WITH_GRAVE */
+  GDK_Multi_key,       GDK_A,  GDK_asciitilde, 0,      0,      0x00C3, /* LATIN_CAPITAL_LETTER_A_WITH_TILDE */
+  GDK_Multi_key,       GDK_A,  GDK_diaeresis,  0,      0,      0x00C4, /* LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_A,  GDK_acute,      0,      0,      0x00C1, /* LATIN_CAPITAL_LETTER_A_WITH_ACUTE */
+  GDK_Multi_key,       GDK_B,  GDK_period,     0,      0,      0x1E02, /* LATIN_CAPITAL_LETTER_B_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_C,  GDK_comma,      0,      0,      0x00C7, /* LATIN_CAPITAL_LETTER_C_WITH_CEDILLA */
+  GDK_Multi_key,       GDK_C,  GDK_period,     0,      0,      0x010A, /* LATIN_CAPITAL_LETTER_C_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_C,  GDK_slash,      0,      0,      0x00A2, /* CENT_SIGN */
+  GDK_Multi_key,       GDK_C,  GDK_0,  0,      0,      0x00A9, /* COPYRIGHT_SIGN */
+  GDK_Multi_key,       GDK_C,  GDK_less,       0,      0,      0x010C, /* LATIN_CAPITAL_LETTER_C_WITH_CARON */
+  GDK_Multi_key,       GDK_C,  GDK_equal,      0,      0,      0x20AC, /* EURO_SIGN */
+  GDK_Multi_key,       GDK_C,  GDK_O,  0,      0,      0x00A9, /* COPYRIGHT_SIGN */
+  GDK_Multi_key,       GDK_C,  GDK_o,  0,      0,      0x00A9, /* COPYRIGHT_SIGN */
+  GDK_Multi_key,       GDK_C,  GDK_bar,        0,      0,      0x00A2, /* CENT_SIGN */
+  GDK_Multi_key,       GDK_D,  GDK_minus,      0,      0,      0x0110, /* LATIN_CAPITAL_LETTER_D_WITH_STROKE */
+  GDK_Multi_key,       GDK_D,  GDK_period,     0,      0,      0x1E0A, /* LATIN_CAPITAL_LETTER_D_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_E,  GDK_quotedbl,   0,      0,      0x00CB, /* LATIN_CAPITAL_LETTER_E_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_E,  GDK_apostrophe, 0,      0,      0x00C9, /* LATIN_CAPITAL_LETTER_E_WITH_ACUTE */
+  GDK_Multi_key,       GDK_E,  GDK_comma,      0,      0,      0x0118, /* LATIN_CAPITAL_LETTER_E_WITH_OGONEK */
+  GDK_Multi_key,       GDK_E,  GDK_minus,      0,      0,      0x0112, /* LATIN_CAPITAL_LETTER_E_WITH_MACRON */
+  GDK_Multi_key,       GDK_E,  GDK_period,     0,      0,      0x0116, /* LATIN_CAPITAL_LETTER_E_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_E,  GDK_greater,    0,      0,      0x00CA, /* LATIN_CAPITAL_LETTER_E_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_E,  GDK_asciicircum,        0,      0,      0x00CA, /* LATIN_CAPITAL_LETTER_E_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_E,  GDK_underscore, 0,      0,      0x0112, /* LATIN_CAPITAL_LETTER_E_WITH_MACRON */
+  GDK_Multi_key,       GDK_E,  GDK_grave,      0,      0,      0x00C8, /* LATIN_CAPITAL_LETTER_E_WITH_GRAVE */
+  GDK_Multi_key,       GDK_E,  GDK_diaeresis,  0,      0,      0x00CB, /* LATIN_CAPITAL_LETTER_E_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_E,  GDK_acute,      0,      0,      0x00C9, /* LATIN_CAPITAL_LETTER_E_WITH_ACUTE */
+  GDK_Multi_key,       GDK_F,  GDK_period,     0,      0,      0x1E1E, /* LATIN_CAPITAL_LETTER_F_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_G,  GDK_parenleft,  0,      0,      0x011E, /* LATIN_CAPITAL_LETTER_G_WITH_BREVE */
+  GDK_Multi_key,       GDK_G,  GDK_comma,      0,      0,      0x0122, /* LATIN_CAPITAL_LETTER_G_WITH_CEDILLA */
+  GDK_Multi_key,       GDK_G,  GDK_period,     0,      0,      0x0120, /* LATIN_CAPITAL_LETTER_G_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_G,  GDK_U,  0,      0,      0x011E, /* LATIN_CAPITAL_LETTER_G_WITH_BREVE */
+  GDK_Multi_key,       GDK_G,  GDK_breve,      0,      0,      0x011E, /* LATIN_CAPITAL_LETTER_G_WITH_BREVE */
+  GDK_Multi_key,       GDK_I,  GDK_quotedbl,   0,      0,      0x00CF, /* LATIN_CAPITAL_LETTER_I_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_I,  GDK_apostrophe, 0,      0,      0x00CD, /* LATIN_CAPITAL_LETTER_I_WITH_ACUTE */
+  GDK_Multi_key,       GDK_I,  GDK_comma,      0,      0,      0x012E, /* LATIN_CAPITAL_LETTER_I_WITH_OGONEK */
+  GDK_Multi_key,       GDK_I,  GDK_minus,      0,      0,      0x012A, /* LATIN_CAPITAL_LETTER_I_WITH_MACRON */
+  GDK_Multi_key,       GDK_I,  GDK_period,     0,      0,      0x0130, /* LATIN_CAPITAL_LETTER_I_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_I,  GDK_greater,    0,      0,      0x00CE, /* LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_I,  GDK_asciicircum,        0,      0,      0x00CE, /* LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_I,  GDK_underscore, 0,      0,      0x012A, /* LATIN_CAPITAL_LETTER_I_WITH_MACRON */
+  GDK_Multi_key,       GDK_I,  GDK_grave,      0,      0,      0x00CC, /* LATIN_CAPITAL_LETTER_I_WITH_GRAVE */
+  GDK_Multi_key,       GDK_I,  GDK_asciitilde, 0,      0,      0x0128, /* LATIN_CAPITAL_LETTER_I_WITH_TILDE */
+  GDK_Multi_key,       GDK_I,  GDK_diaeresis,  0,      0,      0x00CF, /* LATIN_CAPITAL_LETTER_I_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_I,  GDK_acute,      0,      0,      0x00CD, /* LATIN_CAPITAL_LETTER_I_WITH_ACUTE */
+  GDK_Multi_key,       GDK_K,  GDK_comma,      0,      0,      0x0136, /* LATIN_CAPITAL_LETTER_K_WITH_CEDILLA */
+  GDK_Multi_key,       GDK_L,  GDK_comma,      0,      0,      0x013B, /* LATIN_CAPITAL_LETTER_L_WITH_CEDILLA */
+  GDK_Multi_key,       GDK_L,  GDK_minus,      0,      0,      0x00A3, /* POUND_SIGN */
+  GDK_Multi_key,       GDK_L,  GDK_equal,      0,      0,      0x00A3, /* POUND_SIGN */
+  GDK_Multi_key,       GDK_L,  GDK_V,  0,      0,      0x007C, /* VERTICAL_LINE */
+  GDK_Multi_key,       GDK_M,  GDK_period,     0,      0,      0x1E40, /* LATIN_CAPITAL_LETTER_M_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_N,  GDK_comma,      0,      0,      0x0145, /* LATIN_CAPITAL_LETTER_N_WITH_CEDILLA */
+  GDK_Multi_key,       GDK_N,  GDK_minus,      0,      0,      0x00D1, /* LATIN_CAPITAL_LETTER_N_WITH_TILDE */
+  GDK_Multi_key,       GDK_N,  GDK_G,  0,      0,      0x014A, /* LATIN_CAPITAL_LETTER_ENG */
+  GDK_Multi_key,       GDK_N,  GDK_asciitilde, 0,      0,      0x00D1, /* LATIN_CAPITAL_LETTER_N_WITH_TILDE */
+  GDK_Multi_key,       GDK_O,  GDK_quotedbl,   0,      0,      0x00D6, /* LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_O,  GDK_apostrophe, 0,      0,      0x00D3, /* LATIN_CAPITAL_LETTER_O_WITH_ACUTE */
+  GDK_Multi_key,       GDK_O,  GDK_minus,      0,      0,      0x00D5, /* LATIN_CAPITAL_LETTER_O_WITH_TILDE */
+  GDK_Multi_key,       GDK_O,  GDK_slash,      0,      0,      0x00D8, /* LATIN_CAPITAL_LETTER_O_WITH_STROKE */
+  GDK_Multi_key,       GDK_O,  GDK_greater,    0,      0,      0x00D4, /* LATIN_CAPITAL_LETTER_O_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_O,  GDK_C,  0,      0,      0x00A9, /* COPYRIGHT_SIGN */
+  GDK_Multi_key,       GDK_O,  GDK_E,  0,      0,      0x0152, /* LATIN_CAPITAL_LIGATURE_OE */
+  GDK_Multi_key,       GDK_O,  GDK_R,  0,      0,      0x00AE, /* REGISTERED_SIGN */
+  GDK_Multi_key,       GDK_O,  GDK_S,  0,      0,      0x00A7, /* SECTION_SIGN */
+  GDK_Multi_key,       GDK_O,  GDK_X,  0,      0,      0x00A4, /* CURRENCY_SIGN */
+  GDK_Multi_key,       GDK_O,  GDK_asciicircum,        0,      0,      0x00D4, /* LATIN_CAPITAL_LETTER_O_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_O,  GDK_underscore, 0,      0,      0x00BA, /* MASCULINE_ORDINAL_INDICATOR */
+  GDK_Multi_key,       GDK_O,  GDK_grave,      0,      0,      0x00D2, /* LATIN_CAPITAL_LETTER_O_WITH_GRAVE */
+  GDK_Multi_key,       GDK_O,  GDK_c,  0,      0,      0x00A9, /* COPYRIGHT_SIGN */
+  GDK_Multi_key,       GDK_O,  GDK_x,  0,      0,      0x00A4, /* CURRENCY_SIGN */
+  GDK_Multi_key,       GDK_O,  GDK_asciitilde, 0,      0,      0x00D5, /* LATIN_CAPITAL_LETTER_O_WITH_TILDE */
+  GDK_Multi_key,       GDK_O,  GDK_diaeresis,  0,      0,      0x00D6, /* LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_O,  GDK_acute,      0,      0,      0x00D3, /* LATIN_CAPITAL_LETTER_O_WITH_ACUTE */
+  GDK_Multi_key,       GDK_P,  GDK_exclam,     0,      0,      0x00B6, /* PILCROW_SIGN */
+  GDK_Multi_key,       GDK_P,  GDK_period,     0,      0,      0x1E56, /* LATIN_CAPITAL_LETTER_P_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_R,  GDK_comma,      0,      0,      0x0156, /* LATIN_CAPITAL_LETTER_R_WITH_CEDILLA */
+  GDK_Multi_key,       GDK_R,  GDK_O,  0,      0,      0x00AE, /* REGISTERED_SIGN */
+  GDK_Multi_key,       GDK_S,  GDK_exclam,     0,      0,      0x00A7, /* SECTION_SIGN */
+  GDK_Multi_key,       GDK_S,  GDK_comma,      0,      0,      0x015E, /* LATIN_CAPITAL_LETTER_S_WITH_CEDILLA */
+  GDK_Multi_key,       GDK_S,  GDK_period,     0,      0,      0x1E60, /* LATIN_CAPITAL_LETTER_S_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_S,  GDK_0,  0,      0,      0x00A7, /* SECTION_SIGN */
+  GDK_Multi_key,       GDK_S,  GDK_1,  0,      0,      0x00B9, /* SUPERSCRIPT_ONE */
+  GDK_Multi_key,       GDK_S,  GDK_2,  0,      0,      0x00B2, /* SUPERSCRIPT_TWO */
+  GDK_Multi_key,       GDK_S,  GDK_3,  0,      0,      0x00B3, /* SUPERSCRIPT_THREE */
+  GDK_Multi_key,       GDK_S,  GDK_less,       0,      0,      0x0160, /* LATIN_CAPITAL_LETTER_S_WITH_CARON */
+  GDK_Multi_key,       GDK_S,  GDK_O,  0,      0,      0x00A7, /* SECTION_SIGN */
+  GDK_Multi_key,       GDK_S,  GDK_cedilla,    0,      0,      0x015E, /* LATIN_CAPITAL_LETTER_S_WITH_CEDILLA */
+  GDK_Multi_key,       GDK_T,  GDK_minus,      0,      0,      0x0166, /* LATIN_CAPITAL_LETTER_T_WITH_STROKE */
+  GDK_Multi_key,       GDK_T,  GDK_period,     0,      0,      0x1E6A, /* LATIN_CAPITAL_LETTER_T_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_T,  GDK_slash,      0,      0,      0x0166, /* LATIN_CAPITAL_LETTER_T_WITH_STROKE */
+  GDK_Multi_key,       GDK_T,  GDK_H,  0,      0,      0x00DE, /* LATIN_CAPITAL_LETTER_THORN */
+  GDK_Multi_key,       GDK_U,  GDK_quotedbl,   0,      0,      0x00DC, /* LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_U,  GDK_apostrophe, 0,      0,      0x00DA, /* LATIN_CAPITAL_LETTER_U_WITH_ACUTE */
+  GDK_Multi_key,       GDK_U,  GDK_comma,      0,      0,      0x0172, /* LATIN_CAPITAL_LETTER_U_WITH_OGONEK */
+  GDK_Multi_key,       GDK_U,  GDK_minus,      0,      0,      0x00D9, /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */
+  GDK_Multi_key,       GDK_U,  GDK_slash,      0,      0,      0x00B5, /* MICRO_SIGN */
+  GDK_Multi_key,       GDK_U,  GDK_greater,    0,      0,      0x00DB, /* LATIN_CAPITAL_LETTER_U_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_U,  GDK_asciicircum,        0,      0,      0x00DB, /* LATIN_CAPITAL_LETTER_U_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_U,  GDK_underscore, 0,      0,      0x00D9, /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */
+  GDK_Multi_key,       GDK_U,  GDK_grave,      0,      0,      0x00D9, /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */
+  GDK_Multi_key,       GDK_U,  GDK_asciitilde, 0,      0,      0x0168, /* LATIN_CAPITAL_LETTER_U_WITH_TILDE */
+  GDK_Multi_key,       GDK_U,  GDK_diaeresis,  0,      0,      0x00DC, /* LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_U,  GDK_acute,      0,      0,      0x00DA, /* LATIN_CAPITAL_LETTER_U_WITH_ACUTE */
+  GDK_Multi_key,       GDK_V,  GDK_L,  0,      0,      0x007C, /* VERTICAL_LINE */
+  GDK_Multi_key,       GDK_W,  GDK_asciicircum,        0,      0,      0x0174, /* LATIN_CAPITAL_LETTER_W_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_X,  GDK_0,  0,      0,      0x00A4, /* CURRENCY_SIGN */
+  GDK_Multi_key,       GDK_X,  GDK_O,  0,      0,      0x00A4, /* CURRENCY_SIGN */
+  GDK_Multi_key,       GDK_X,  GDK_o,  0,      0,      0x00A4, /* CURRENCY_SIGN */
+  GDK_Multi_key,       GDK_Y,  GDK_quotedbl,   0,      0,      0x0178, /* LATIN_CAPITAL_LETTER_Y_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_Y,  GDK_apostrophe, 0,      0,      0x00DD, /* LATIN_CAPITAL_LETTER_Y_WITH_ACUTE */
+  GDK_Multi_key,       GDK_Y,  GDK_minus,      0,      0,      0x00A5, /* YEN_SIGN */
+  GDK_Multi_key,       GDK_Y,  GDK_equal,      0,      0,      0x00A5, /* YEN_SIGN */
+  GDK_Multi_key,       GDK_Y,  GDK_asciicircum,        0,      0,      0x0176, /* LATIN_CAPITAL_LETTER_Y_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_Y,  GDK_diaeresis,  0,      0,      0x0178, /* LATIN_CAPITAL_LETTER_Y_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_Y,  GDK_acute,      0,      0,      0x00DD, /* LATIN_CAPITAL_LETTER_Y_WITH_ACUTE */
+  GDK_Multi_key,       GDK_Z,  GDK_less,       0,      0,      0x017D, /* LATIN_CAPITAL_LETTER_Z_WITH_CARON */
+  GDK_Multi_key,       GDK_asciicircum,        GDK_space,      0,      0,      0x005E, /* CIRCUMFLEX_ACCENT */
+  GDK_Multi_key,       GDK_asciicircum,        GDK_minus,      0,      0,      0x00AF, /* MACRON */
+  GDK_Multi_key,       GDK_asciicircum,        GDK_period,     0,      0,      0x00B7, /* MIDDLE_DOT */
+  GDK_Multi_key,       GDK_asciicircum,        GDK_slash,      0,      0,      0x007C, /* VERTICAL_LINE */
+  GDK_Multi_key,       GDK_asciicircum,        GDK_0,  0,      0,      0x00B0, /* DEGREE_SIGN */
+  GDK_Multi_key,       GDK_asciicircum,        GDK_1,  0,      0,      0x00B9, /* SUPERSCRIPT_ONE */
+  GDK_Multi_key,       GDK_asciicircum,        GDK_2,  0,      0,      0x00B2, /* SUPERSCRIPT_TWO */
+  GDK_Multi_key,       GDK_asciicircum,        GDK_3,  0,      0,      0x00B3, /* SUPERSCRIPT_THREE */
+  GDK_Multi_key,       GDK_asciicircum,        GDK_A,  0,      0,      0x00C2, /* LATIN_CAPITAL_LETTER_A_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_asciicircum,        GDK_E,  0,      0,      0x00CA, /* LATIN_CAPITAL_LETTER_E_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_asciicircum,        GDK_I,  0,      0,      0x00CE, /* LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_asciicircum,        GDK_O,  0,      0,      0x00D4, /* LATIN_CAPITAL_LETTER_O_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_asciicircum,        GDK_U,  0,      0,      0x00DB, /* LATIN_CAPITAL_LETTER_U_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_asciicircum,        GDK_W,  0,      0,      0x0174, /* LATIN_CAPITAL_LETTER_W_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_asciicircum,        GDK_Y,  0,      0,      0x0176, /* LATIN_CAPITAL_LETTER_Y_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_asciicircum,        GDK_underscore, 0,      0,      0x00AF, /* MACRON */
+  GDK_Multi_key,       GDK_asciicircum,        GDK_a,  0,      0,      0x00E2, /* LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_asciicircum,        GDK_e,  0,      0,      0x00EA, /* LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_asciicircum,        GDK_i,  0,      0,      0x00EE, /* LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_asciicircum,        GDK_o,  0,      0,      0x00F4, /* LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_asciicircum,        GDK_u,  0,      0,      0x00FB, /* LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_asciicircum,        GDK_w,  0,      0,      0x0175, /* LATIN_SMALL_LETTER_W_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_asciicircum,        GDK_y,  0,      0,      0x0177, /* LATIN_SMALL_LETTER_Y_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_underscore, GDK_A,  0,      0,      0x00AA, /* FEMININE_ORDINAL_INDICATOR */
+  GDK_Multi_key,       GDK_underscore, GDK_E,  0,      0,      0x0112, /* LATIN_CAPITAL_LETTER_E_WITH_MACRON */
+  GDK_Multi_key,       GDK_underscore, GDK_I,  0,      0,      0x012A, /* LATIN_CAPITAL_LETTER_I_WITH_MACRON */
+  GDK_Multi_key,       GDK_underscore, GDK_O,  0,      0,      0x00BA, /* MASCULINE_ORDINAL_INDICATOR */
+  GDK_Multi_key,       GDK_underscore, GDK_U,  0,      0,      0x00D9, /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */
+  GDK_Multi_key,       GDK_underscore, GDK_asciicircum,        0,      0,      0x00AF, /* MACRON */
+  GDK_Multi_key,       GDK_underscore, GDK_underscore, 0,      0,      0x00AF, /* MACRON */
+  GDK_Multi_key,       GDK_underscore, GDK_a,  0,      0,      0x00AA, /* FEMININE_ORDINAL_INDICATOR */
+  GDK_Multi_key,       GDK_underscore, GDK_e,  0,      0,      0x0113, /* LATIN_SMALL_LETTER_E_WITH_MACRON */
+  GDK_Multi_key,       GDK_underscore, GDK_i,  0,      0,      0x012B, /* LATIN_SMALL_LETTER_I_WITH_MACRON */
+  GDK_Multi_key,       GDK_underscore, GDK_o,  0,      0,      0x00BA, /* MASCULINE_ORDINAL_INDICATOR */
+  GDK_Multi_key,       GDK_underscore, GDK_u,  0,      0,      0x016B, /* LATIN_SMALL_LETTER_U_WITH_MACRON */
+  GDK_Multi_key,       GDK_grave,      GDK_space,      0,      0,      0x0060, /* GRAVE_ACCENT */
+  GDK_Multi_key,       GDK_grave,      GDK_A,  0,      0,      0x00C0, /* LATIN_CAPITAL_LETTER_A_WITH_GRAVE */
+  GDK_Multi_key,       GDK_grave,      GDK_E,  0,      0,      0x00C8, /* LATIN_CAPITAL_LETTER_E_WITH_GRAVE */
+  GDK_Multi_key,       GDK_grave,      GDK_I,  0,      0,      0x00CC, /* LATIN_CAPITAL_LETTER_I_WITH_GRAVE */
+  GDK_Multi_key,       GDK_grave,      GDK_O,  0,      0,      0x00D2, /* LATIN_CAPITAL_LETTER_O_WITH_GRAVE */
+  GDK_Multi_key,       GDK_grave,      GDK_U,  0,      0,      0x00D9, /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */
+  GDK_Multi_key,       GDK_grave,      GDK_a,  0,      0,      0x00E0, /* LATIN_SMALL_LETTER_A_WITH_GRAVE */
+  GDK_Multi_key,       GDK_grave,      GDK_e,  0,      0,      0x00E8, /* LATIN_SMALL_LETTER_E_WITH_GRAVE */
+  GDK_Multi_key,       GDK_grave,      GDK_i,  0,      0,      0x00EC, /* LATIN_SMALL_LETTER_I_WITH_GRAVE */
+  GDK_Multi_key,       GDK_grave,      GDK_o,  0,      0,      0x00F2, /* LATIN_SMALL_LETTER_O_WITH_GRAVE */
+  GDK_Multi_key,       GDK_grave,      GDK_u,  0,      0,      0x00F9, /* LATIN_SMALL_LETTER_U_WITH_GRAVE */
+  GDK_Multi_key,       GDK_a,  GDK_quotedbl,   0,      0,      0x00E4, /* LATIN_SMALL_LETTER_A_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_a,  GDK_apostrophe, 0,      0,      0x00E1, /* LATIN_SMALL_LETTER_A_WITH_ACUTE */
+  GDK_Multi_key,       GDK_a,  GDK_asterisk,   0,      0,      0x00E5, /* LATIN_SMALL_LETTER_A_WITH_RING_ABOVE */
+  GDK_Multi_key,       GDK_a,  GDK_comma,      0,      0,      0x0105, /* LATIN_SMALL_LETTER_A_WITH_OGONEK */
+  GDK_Multi_key,       GDK_a,  GDK_minus,      0,      0,      0x00E3, /* LATIN_SMALL_LETTER_A_WITH_TILDE */
+  GDK_Multi_key,       GDK_a,  GDK_greater,    0,      0,      0x00E2, /* LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_a,  GDK_asciicircum,        0,      0,      0x00E2, /* LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_a,  GDK_underscore, 0,      0,      0x00AA, /* FEMININE_ORDINAL_INDICATOR */
+  GDK_Multi_key,       GDK_a,  GDK_grave,      0,      0,      0x00E0, /* LATIN_SMALL_LETTER_A_WITH_GRAVE */
+  GDK_Multi_key,       GDK_a,  GDK_a,  0,      0,      0x00E5, /* LATIN_SMALL_LETTER_A_WITH_RING_ABOVE */
+  GDK_Multi_key,       GDK_a,  GDK_e,  0,      0,      0x00E6, /* LATIN_SMALL_LETTER_AE */
+  GDK_Multi_key,       GDK_a,  GDK_asciitilde, 0,      0,      0x00E3, /* LATIN_SMALL_LETTER_A_WITH_TILDE */
+  GDK_Multi_key,       GDK_a,  GDK_diaeresis,  0,      0,      0x00E4, /* LATIN_SMALL_LETTER_A_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_a,  GDK_acute,      0,      0,      0x00E1, /* LATIN_SMALL_LETTER_A_WITH_ACUTE */
+  GDK_Multi_key,       GDK_b,  GDK_period,     0,      0,      0x1E03, /* LATIN_SMALL_LETTER_B_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_c,  GDK_comma,      0,      0,      0x00E7, /* LATIN_SMALL_LETTER_C_WITH_CEDILLA */
+  GDK_Multi_key,       GDK_c,  GDK_period,     0,      0,      0x010B, /* LATIN_SMALL_LETTER_C_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_c,  GDK_slash,      0,      0,      0x00A2, /* CENT_SIGN */
+  GDK_Multi_key,       GDK_c,  GDK_0,  0,      0,      0x00A9, /* COPYRIGHT_SIGN */
+  GDK_Multi_key,       GDK_c,  GDK_less,       0,      0,      0x010D, /* LATIN_SMALL_LETTER_C_WITH_CARON */
+  GDK_Multi_key,       GDK_c,  GDK_O,  0,      0,      0x00A9, /* COPYRIGHT_SIGN */
+  GDK_Multi_key,       GDK_c,  GDK_o,  0,      0,      0x00A9, /* COPYRIGHT_SIGN */
+  GDK_Multi_key,       GDK_c,  GDK_bar,        0,      0,      0x00A2, /* CENT_SIGN */
+  GDK_Multi_key,       GDK_d,  GDK_minus,      0,      0,      0x0111, /* LATIN_SMALL_LETTER_D_WITH_STROKE */
+  GDK_Multi_key,       GDK_d,  GDK_period,     0,      0,      0x1E0B, /* LATIN_SMALL_LETTER_D_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_e,  GDK_quotedbl,   0,      0,      0x00EB, /* LATIN_SMALL_LETTER_E_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_e,  GDK_apostrophe, 0,      0,      0x00E9, /* LATIN_SMALL_LETTER_E_WITH_ACUTE */
+  GDK_Multi_key,       GDK_e,  GDK_comma,      0,      0,      0x0119, /* LATIN_SMALL_LETTER_E_WITH_OGONEK */
+  GDK_Multi_key,       GDK_e,  GDK_minus,      0,      0,      0x0113, /* LATIN_SMALL_LETTER_E_WITH_MACRON */
+  GDK_Multi_key,       GDK_e,  GDK_period,     0,      0,      0x0117, /* LATIN_SMALL_LETTER_E_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_e,  GDK_equal,      0,      0,      0x20AC, /* EURO_SIGN */
+  GDK_Multi_key,       GDK_e,  GDK_greater,    0,      0,      0x00EA, /* LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_e,  GDK_asciicircum,        0,      0,      0x00EA, /* LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_e,  GDK_underscore, 0,      0,      0x0113, /* LATIN_SMALL_LETTER_E_WITH_MACRON */
+  GDK_Multi_key,       GDK_e,  GDK_grave,      0,      0,      0x00E8, /* LATIN_SMALL_LETTER_E_WITH_GRAVE */
+  GDK_Multi_key,       GDK_e,  GDK_diaeresis,  0,      0,      0x00EB, /* LATIN_SMALL_LETTER_E_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_e,  GDK_acute,      0,      0,      0x00E9, /* LATIN_SMALL_LETTER_E_WITH_ACUTE */
+  GDK_Multi_key,       GDK_f,  GDK_period,     0,      0,      0x1E1F, /* LATIN_SMALL_LETTER_F_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_g,  GDK_parenleft,  0,      0,      0x011F, /* LATIN_SMALL_LETTER_G_WITH_BREVE */
+  GDK_Multi_key,       GDK_g,  GDK_comma,      0,      0,      0x0123, /* LATIN_SMALL_LETTER_G_WITH_CEDILLA */
+  GDK_Multi_key,       GDK_g,  GDK_period,     0,      0,      0x0121, /* LATIN_SMALL_LETTER_G_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_g,  GDK_U,  0,      0,      0x011F, /* LATIN_SMALL_LETTER_G_WITH_BREVE */
+  GDK_Multi_key,       GDK_g,  GDK_breve,      0,      0,      0x011F, /* LATIN_SMALL_LETTER_G_WITH_BREVE */
+  GDK_Multi_key,       GDK_i,  GDK_quotedbl,   0,      0,      0x00EF, /* LATIN_SMALL_LETTER_I_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_i,  GDK_apostrophe, 0,      0,      0x00ED, /* LATIN_SMALL_LETTER_I_WITH_ACUTE */
+  GDK_Multi_key,       GDK_i,  GDK_comma,      0,      0,      0x012F, /* LATIN_SMALL_LETTER_I_WITH_OGONEK */
+  GDK_Multi_key,       GDK_i,  GDK_minus,      0,      0,      0x012B, /* LATIN_SMALL_LETTER_I_WITH_MACRON */
+  GDK_Multi_key,       GDK_i,  GDK_period,     0,      0,      0x0131, /* LATIN_SMALL_LETTER_DOTLESS_I */
+  GDK_Multi_key,       GDK_i,  GDK_greater,    0,      0,      0x00EE, /* LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_i,  GDK_asciicircum,        0,      0,      0x00EE, /* LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_i,  GDK_underscore, 0,      0,      0x012B, /* LATIN_SMALL_LETTER_I_WITH_MACRON */
+  GDK_Multi_key,       GDK_i,  GDK_grave,      0,      0,      0x00EC, /* LATIN_SMALL_LETTER_I_WITH_GRAVE */
+  GDK_Multi_key,       GDK_i,  GDK_asciitilde, 0,      0,      0x0129, /* LATIN_SMALL_LETTER_I_WITH_TILDE */
+  GDK_Multi_key,       GDK_i,  GDK_diaeresis,  0,      0,      0x00EF, /* LATIN_SMALL_LETTER_I_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_i,  GDK_acute,      0,      0,      0x00ED, /* LATIN_SMALL_LETTER_I_WITH_ACUTE */
+  GDK_Multi_key,       GDK_k,  GDK_comma,      0,      0,      0x0137, /* LATIN_SMALL_LETTER_K_WITH_CEDILLA */
+  GDK_Multi_key,       GDK_k,  GDK_k,  0,      0,      0x0138, /* LATIN_SMALL_LETTER_KRA */
+  GDK_Multi_key,       GDK_l,  GDK_comma,      0,      0,      0x013C, /* LATIN_SMALL_LETTER_L_WITH_CEDILLA */
+  GDK_Multi_key,       GDK_l,  GDK_minus,      0,      0,      0x00A3, /* POUND_SIGN */
+  GDK_Multi_key,       GDK_l,  GDK_equal,      0,      0,      0x00A3, /* POUND_SIGN */
+  GDK_Multi_key,       GDK_l,  GDK_v,  0,      0,      0x007C, /* VERTICAL_LINE */
+  GDK_Multi_key,       GDK_m,  GDK_period,     0,      0,      0x1E41, /* LATIN_SMALL_LETTER_M_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_n,  GDK_comma,      0,      0,      0x0146, /* LATIN_SMALL_LETTER_N_WITH_CEDILLA */
+  GDK_Multi_key,       GDK_n,  GDK_minus,      0,      0,      0x00F1, /* LATIN_SMALL_LETTER_N_WITH_TILDE */
+  GDK_Multi_key,       GDK_n,  GDK_g,  0,      0,      0x014B, /* LATIN_SMALL_LETTER_ENG */
+  GDK_Multi_key,       GDK_n,  GDK_asciitilde, 0,      0,      0x00F1, /* LATIN_SMALL_LETTER_N_WITH_TILDE */
+  GDK_Multi_key,       GDK_o,  GDK_quotedbl,   0,      0,      0x00F6, /* LATIN_SMALL_LETTER_O_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_o,  GDK_apostrophe, 0,      0,      0x00F3, /* LATIN_SMALL_LETTER_O_WITH_ACUTE */
+  GDK_Multi_key,       GDK_o,  GDK_minus,      0,      0,      0x00F5, /* LATIN_SMALL_LETTER_O_WITH_TILDE */
+  GDK_Multi_key,       GDK_o,  GDK_slash,      0,      0,      0x00F8, /* LATIN_SMALL_LETTER_O_WITH_STROKE */
+  GDK_Multi_key,       GDK_o,  GDK_greater,    0,      0,      0x00F4, /* LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_o,  GDK_C,  0,      0,      0x00A9, /* COPYRIGHT_SIGN */
+  GDK_Multi_key,       GDK_o,  GDK_X,  0,      0,      0x00A4, /* CURRENCY_SIGN */
+  GDK_Multi_key,       GDK_o,  GDK_asciicircum,        0,      0,      0x00F4, /* LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_o,  GDK_underscore, 0,      0,      0x00BA, /* MASCULINE_ORDINAL_INDICATOR */
+  GDK_Multi_key,       GDK_o,  GDK_grave,      0,      0,      0x00F2, /* LATIN_SMALL_LETTER_O_WITH_GRAVE */
+  GDK_Multi_key,       GDK_o,  GDK_c,  0,      0,      0x00A9, /* COPYRIGHT_SIGN */
+  GDK_Multi_key,       GDK_o,  GDK_e,  0,      0,      0x0153, /* LATIN_SMALL_LIGATURE_OE */
+  GDK_Multi_key,       GDK_o,  GDK_s,  0,      0,      0x00A7, /* SECTION_SIGN */
+  GDK_Multi_key,       GDK_o,  GDK_x,  0,      0,      0x00A4, /* CURRENCY_SIGN */
+  GDK_Multi_key,       GDK_o,  GDK_asciitilde, 0,      0,      0x00F5, /* LATIN_SMALL_LETTER_O_WITH_TILDE */
+  GDK_Multi_key,       GDK_o,  GDK_diaeresis,  0,      0,      0x00F6, /* LATIN_SMALL_LETTER_O_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_o,  GDK_acute,      0,      0,      0x00F3, /* LATIN_SMALL_LETTER_O_WITH_ACUTE */
+  GDK_Multi_key,       GDK_p,  GDK_exclam,     0,      0,      0x00B6, /* PILCROW_SIGN */
+  GDK_Multi_key,       GDK_p,  GDK_period,     0,      0,      0x1E57, /* LATIN_SMALL_LETTER_P_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_r,  GDK_comma,      0,      0,      0x0157, /* LATIN_SMALL_LETTER_R_WITH_CEDILLA */
+  GDK_Multi_key,       GDK_s,  GDK_exclam,     0,      0,      0x00A7, /* SECTION_SIGN */
+  GDK_Multi_key,       GDK_s,  GDK_comma,      0,      0,      0x015F, /* LATIN_SMALL_LETTER_S_WITH_CEDILLA */
+  GDK_Multi_key,       GDK_s,  GDK_period,     0,      0,      0x1E61, /* LATIN_SMALL_LETTER_S_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_s,  GDK_0,  0,      0,      0x00A7, /* SECTION_SIGN */
+  GDK_Multi_key,       GDK_s,  GDK_1,  0,      0,      0x00B9, /* SUPERSCRIPT_ONE */
+  GDK_Multi_key,       GDK_s,  GDK_2,  0,      0,      0x00B2, /* SUPERSCRIPT_TWO */
+  GDK_Multi_key,       GDK_s,  GDK_3,  0,      0,      0x00B3, /* SUPERSCRIPT_THREE */
+  GDK_Multi_key,       GDK_s,  GDK_less,       0,      0,      0x0161, /* LATIN_SMALL_LETTER_S_WITH_CARON */
+  GDK_Multi_key,       GDK_s,  GDK_o,  0,      0,      0x00A7, /* SECTION_SIGN */
+  GDK_Multi_key,       GDK_s,  GDK_s,  0,      0,      0x00DF, /* LATIN_SMALL_LETTER_SHARP_S */
+  GDK_Multi_key,       GDK_s,  GDK_cedilla,    0,      0,      0x015F, /* LATIN_SMALL_LETTER_S_WITH_CEDILLA */
+  GDK_Multi_key,       GDK_t,  GDK_minus,      0,      0,      0x0167, /* LATIN_SMALL_LETTER_T_WITH_STROKE */
+  GDK_Multi_key,       GDK_t,  GDK_period,     0,      0,      0x1E6B, /* LATIN_SMALL_LETTER_T_WITH_DOT_ABOVE */
+  GDK_Multi_key,       GDK_t,  GDK_slash,      0,      0,      0x0167, /* LATIN_SMALL_LETTER_T_WITH_STROKE */
+  GDK_Multi_key,       GDK_t,  GDK_h,  0,      0,      0x00FE, /* LATIN_SMALL_LETTER_THORN */
+  GDK_Multi_key,       GDK_u,  GDK_quotedbl,   0,      0,      0x00FC, /* LATIN_SMALL_LETTER_U_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_u,  GDK_apostrophe, 0,      0,      0x00FA, /* LATIN_SMALL_LETTER_U_WITH_ACUTE */
+  GDK_Multi_key,       GDK_u,  GDK_comma,      0,      0,      0x0173, /* LATIN_SMALL_LETTER_U_WITH_OGONEK */
+  GDK_Multi_key,       GDK_u,  GDK_minus,      0,      0,      0x016B, /* LATIN_SMALL_LETTER_U_WITH_MACRON */
+  GDK_Multi_key,       GDK_u,  GDK_slash,      0,      0,      0x00B5, /* MICRO_SIGN */
+  GDK_Multi_key,       GDK_u,  GDK_greater,    0,      0,      0x00FB, /* LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_u,  GDK_asciicircum,        0,      0,      0x00FB, /* LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_u,  GDK_underscore, 0,      0,      0x016B, /* LATIN_SMALL_LETTER_U_WITH_MACRON */
+  GDK_Multi_key,       GDK_u,  GDK_grave,      0,      0,      0x00F9, /* LATIN_SMALL_LETTER_U_WITH_GRAVE */
+  GDK_Multi_key,       GDK_u,  GDK_asciitilde, 0,      0,      0x0169, /* LATIN_SMALL_LETTER_U_WITH_TILDE */
+  GDK_Multi_key,       GDK_u,  GDK_diaeresis,  0,      0,      0x00FC, /* LATIN_SMALL_LETTER_U_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_u,  GDK_acute,      0,      0,      0x00FA, /* LATIN_SMALL_LETTER_U_WITH_ACUTE */
+  GDK_Multi_key,       GDK_v,  GDK_Z,  0,      0,      0x017D, /* LATIN_CAPITAL_LETTER_Z_WITH_CARON */
+  GDK_Multi_key,       GDK_v,  GDK_l,  0,      0,      0x007C, /* VERTICAL_LINE */
+  GDK_Multi_key,       GDK_v,  GDK_z,  0,      0,      0x017E, /* LATIN_SMALL_LETTER_Z_WITH_CARON */
+  GDK_Multi_key,       GDK_w,  GDK_asciicircum,        0,      0,      0x0175, /* LATIN_SMALL_LETTER_W_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_x,  GDK_0,  0,      0,      0x00A4, /* CURRENCY_SIGN */
+  GDK_Multi_key,       GDK_x,  GDK_O,  0,      0,      0x00A4, /* CURRENCY_SIGN */
+  GDK_Multi_key,       GDK_x,  GDK_o,  0,      0,      0x00A4, /* CURRENCY_SIGN */
+  GDK_Multi_key,       GDK_x,  GDK_x,  0,      0,      0x00D7, /* MULTIPLICATION_SIGN */
+  GDK_Multi_key,       GDK_y,  GDK_quotedbl,   0,      0,      0x00FF, /* LATIN_SMALL_LETTER_Y_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_y,  GDK_apostrophe, 0,      0,      0x00FD, /* LATIN_SMALL_LETTER_Y_WITH_ACUTE */
+  GDK_Multi_key,       GDK_y,  GDK_minus,      0,      0,      0x00A5, /* YEN_SIGN */
+  GDK_Multi_key,       GDK_y,  GDK_equal,      0,      0,      0x00A5, /* YEN_SIGN */
+  GDK_Multi_key,       GDK_y,  GDK_asciicircum,        0,      0,      0x0177, /* LATIN_SMALL_LETTER_Y_WITH_CIRCUMFLEX */
+  GDK_Multi_key,       GDK_y,  GDK_diaeresis,  0,      0,      0x00FF, /* LATIN_SMALL_LETTER_Y_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_y,  GDK_acute,      0,      0,      0x00FD, /* LATIN_SMALL_LETTER_Y_WITH_ACUTE */
+  GDK_Multi_key,       GDK_z,  GDK_less,       0,      0,      0x017E, /* LATIN_SMALL_LETTER_Z_WITH_CARON */
+  GDK_Multi_key,       GDK_bar,        GDK_C,  0,      0,      0x00A2, /* CENT_SIGN */
+  GDK_Multi_key,       GDK_bar,        GDK_c,  0,      0,      0x00A2, /* CENT_SIGN */
+  GDK_Multi_key,       GDK_asciitilde, GDK_space,      0,      0,      0x007E, /* TILDE */
+  GDK_Multi_key,       GDK_asciitilde, GDK_A,  0,      0,      0x00C3, /* LATIN_CAPITAL_LETTER_A_WITH_TILDE */
+  GDK_Multi_key,       GDK_asciitilde, GDK_I,  0,      0,      0x0128, /* LATIN_CAPITAL_LETTER_I_WITH_TILDE */
+  GDK_Multi_key,       GDK_asciitilde, GDK_N,  0,      0,      0x00D1, /* LATIN_CAPITAL_LETTER_N_WITH_TILDE */
+  GDK_Multi_key,       GDK_asciitilde, GDK_O,  0,      0,      0x00D5, /* LATIN_CAPITAL_LETTER_O_WITH_TILDE */
+  GDK_Multi_key,       GDK_asciitilde, GDK_U,  0,      0,      0x0168, /* LATIN_CAPITAL_LETTER_U_WITH_TILDE */
+  GDK_Multi_key,       GDK_asciitilde, GDK_a,  0,      0,      0x00E3, /* LATIN_SMALL_LETTER_A_WITH_TILDE */
+  GDK_Multi_key,       GDK_asciitilde, GDK_i,  0,      0,      0x0129, /* LATIN_SMALL_LETTER_I_WITH_TILDE */
+  GDK_Multi_key,       GDK_asciitilde, GDK_n,  0,      0,      0x00F1, /* LATIN_SMALL_LETTER_N_WITH_TILDE */
+  GDK_Multi_key,       GDK_asciitilde, GDK_o,  0,      0,      0x00F5, /* LATIN_SMALL_LETTER_O_WITH_TILDE */
+  GDK_Multi_key,       GDK_asciitilde, GDK_u,  0,      0,      0x0169, /* LATIN_SMALL_LETTER_U_WITH_TILDE */
+  GDK_Multi_key,       GDK_diaeresis,  GDK_A,  0,      0,      0x00C4, /* LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_diaeresis,  GDK_E,  0,      0,      0x00CB, /* LATIN_CAPITAL_LETTER_E_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_diaeresis,  GDK_I,  0,      0,      0x00CF, /* LATIN_CAPITAL_LETTER_I_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_diaeresis,  GDK_O,  0,      0,      0x00D6, /* LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_diaeresis,  GDK_U,  0,      0,      0x00DC, /* LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_diaeresis,  GDK_Y,  0,      0,      0x0178, /* LATIN_CAPITAL_LETTER_Y_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_diaeresis,  GDK_a,  0,      0,      0x00E4, /* LATIN_SMALL_LETTER_A_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_diaeresis,  GDK_e,  0,      0,      0x00EB, /* LATIN_SMALL_LETTER_E_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_diaeresis,  GDK_i,  0,      0,      0x00EF, /* LATIN_SMALL_LETTER_I_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_diaeresis,  GDK_o,  0,      0,      0x00F6, /* LATIN_SMALL_LETTER_O_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_diaeresis,  GDK_u,  0,      0,      0x00FC, /* LATIN_SMALL_LETTER_U_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_diaeresis,  GDK_y,  0,      0,      0x00FF, /* LATIN_SMALL_LETTER_Y_WITH_DIAERESIS */
+  GDK_Multi_key,       GDK_acute,      GDK_A,  0,      0,      0x00C1, /* LATIN_CAPITAL_LETTER_A_WITH_ACUTE */
+  GDK_Multi_key,       GDK_acute,      GDK_E,  0,      0,      0x00C9, /* LATIN_CAPITAL_LETTER_E_WITH_ACUTE */
+  GDK_Multi_key,       GDK_acute,      GDK_I,  0,      0,      0x00CD, /* LATIN_CAPITAL_LETTER_I_WITH_ACUTE */
+  GDK_Multi_key,       GDK_acute,      GDK_O,  0,      0,      0x00D3, /* LATIN_CAPITAL_LETTER_O_WITH_ACUTE */
+  GDK_Multi_key,       GDK_acute,      GDK_U,  0,      0,      0x00DA, /* LATIN_CAPITAL_LETTER_U_WITH_ACUTE */
+  GDK_Multi_key,       GDK_acute,      GDK_Y,  0,      0,      0x00DD, /* LATIN_CAPITAL_LETTER_Y_WITH_ACUTE */
+  GDK_Multi_key,       GDK_acute,      GDK_a,  0,      0,      0x00E1, /* LATIN_SMALL_LETTER_A_WITH_ACUTE */
+  GDK_Multi_key,       GDK_acute,      GDK_e,  0,      0,      0x00E9, /* LATIN_SMALL_LETTER_E_WITH_ACUTE */
+  GDK_Multi_key,       GDK_acute,      GDK_i,  0,      0,      0x00ED, /* LATIN_SMALL_LETTER_I_WITH_ACUTE */
+  GDK_Multi_key,       GDK_acute,      GDK_o,  0,      0,      0x00F3, /* LATIN_SMALL_LETTER_O_WITH_ACUTE */
+  GDK_Multi_key,       GDK_acute,      GDK_u,  0,      0,      0x00FA, /* LATIN_SMALL_LETTER_U_WITH_ACUTE */
+  GDK_Multi_key,       GDK_acute,      GDK_y,  0,      0,      0x00FD, /* LATIN_SMALL_LETTER_Y_WITH_ACUTE */
+  GDK_Multi_key,       GDK_cedilla,    GDK_S,  0,      0,      0x015E, /* LATIN_CAPITAL_LETTER_S_WITH_CEDILLA */
+  GDK_Multi_key,       GDK_cedilla,    GDK_s,  0,      0,      0x015F, /* LATIN_SMALL_LETTER_S_WITH_CEDILLA */
+  GDK_Multi_key,       GDK_breve,      GDK_G,  0,      0,      0x011E, /* LATIN_CAPITAL_LETTER_G_WITH_BREVE */
+  GDK_Multi_key,       GDK_breve,      GDK_g,  0,      0,      0x011F, /* LATIN_SMALL_LETTER_G_WITH_BREVE */
+};
+
+static const GtkComposeTable gtk_compose_table = {
+  gtk_compose_seqs,
+  4,
+  G_N_ELEMENTS (gtk_compose_seqs) / 6
 };
 
 guint16 gtk_compose_ignore[] = {
@@ -732,11 +739,18 @@ guint16 gtk_compose_ignore[] = {
   GDK_Hyper_R 
 };
 
-static void     gtk_im_context_simple_class_init (GtkIMContextSimpleClass *class);
-static void     gtk_im_context_simple_init (GtkIMContextSimple *im_context_simple);
+static void     gtk_im_context_simple_class_init         (GtkIMContextSimpleClass  *class);
+static void     gtk_im_context_simple_init               (GtkIMContextSimple       *im_context_simple);
+static void     gtk_im_context_simple_finalize           (GObject                  *obj);
+static gboolean gtk_im_context_simple_filter_keypress    (GtkIMContext             *context,
+                                                         GdkEventKey              *key);
+static void     gtk_im_context_simple_reset              (GtkIMContext             *context);
+static void     gtk_im_context_simple_get_preedit_string (GtkIMContext             *context,
+                                                         gchar                   **str,
+                                                         PangoAttrList           **attrs,
+                                                         gint                     *cursor_pos);
 
-static gboolean gtk_im_context_simple_filter_keypress (GtkIMContext *context,
-                                                      GdkEventKey  *key);
+static GObjectClass *parent_class;
 
 GtkType
 gtk_im_context_simple_get_type (void)
@@ -767,8 +781,14 @@ static void
 gtk_im_context_simple_class_init (GtkIMContextSimpleClass *class)
 {
   GtkIMContextClass *im_context_class = GTK_IM_CONTEXT_CLASS (class);
-  
+  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+
+  parent_class = g_type_class_peek_parent (class);
+
   im_context_class->filter_keypress = gtk_im_context_simple_filter_keypress;
+  im_context_class->reset = gtk_im_context_simple_reset;
+  im_context_class->get_preedit_string = gtk_im_context_simple_get_preedit_string;
+  gobject_class->finalize = gtk_im_context_simple_finalize;
 }
 
 static void
@@ -776,6 +796,14 @@ gtk_im_context_simple_init (GtkIMContextSimple *im_context_simple)
 {
 }
 
+static void
+gtk_im_context_simple_finalize (GObject *obj)
+{
+  GtkIMContextSimple *context_simple = GTK_IM_CONTEXT_SIMPLE (obj);
+
+  g_slist_free (context_simple->tables);
+}
+
 GtkIMContext *
 gtk_im_context_simple_new (void)
 {
@@ -788,10 +816,20 @@ gtk_im_context_simple_commit_char (GtkIMContext *context,
 {
   gchar buf[10];
   gint len;
+
+  GtkIMContextSimple *context_simple = GTK_IM_CONTEXT_SIMPLE (context);
       
   len = g_unichar_to_utf8 (ch, buf);
   buf[len] = '\0';
 
+  if (context_simple->tentative_match)
+    {
+      context_simple->tentative_match = 0;
+      context_simple->tentative_match_len = 0;
+      gtk_signal_emit_by_name (GTK_OBJECT (context_simple),
+                              "preedit-changed");
+    }
+
   gtk_signal_emit_by_name (GTK_OBJECT (context), "commit", &buf);
 }
 
@@ -800,13 +838,13 @@ compare_seq (const void *key, const void *value)
 {
   int i = 0;
   const guint *keysyms = key;
-  const GtkComposeSeq *seq = value;
+  const guint16 *seq = value;
 
   while (keysyms[i])
     {
-      if (keysyms[i] < seq->keysyms[i])
+      if (keysyms[i] < seq[i])
        return -1;
-      else if (keysyms[i] > seq->keysyms[i])
+      else if (keysyms[i] > seq[i])
        return 1;
          
       i++;
@@ -815,12 +853,75 @@ compare_seq (const void *key, const void *value)
   return 0;
 }
 
+static gboolean
+check_table (GtkIMContextSimple    *context_simple,
+            const GtkComposeTable *table,
+            gint                   n_compose)
+{
+  gint row_stride = table->max_seq_len + 2; 
+  guint16 *seq = bsearch (context_simple->compose_buffer,
+                         table->data, table->n_seqs,
+                         sizeof (guint16) *  row_stride, 
+                         compare_seq);
+
+  if (seq)
+    {
+      guint16 *prev_seq;
+
+      /* Back up to the first sequence that matches to make sure
+       * we find the exact match if their is one.
+       */
+      while (seq > table->data)
+       {
+         prev_seq = seq - row_stride;
+         if (compare_seq (context_simple->compose_buffer, prev_seq) != 0)
+           break;
+         seq = prev_seq;
+       }
+      
+      if (n_compose == table->max_seq_len ||
+         seq[n_compose] == 0) /* complete sequence */
+       {
+         guint16 *next_seq;
+         gunichar value = 
+           0x10000 * seq[table->max_seq_len] + seq[table->max_seq_len + 1];
+
+         
+         /* We found a tentative match. See if there are any longer
+          * sequences containing this subsequence
+          */
+         next_seq = seq + row_stride;
+         if (next_seq < table->data + row_stride * table->n_seqs)
+           {
+             if (compare_seq (context_simple->compose_buffer, next_seq) == 0)
+               {
+                 context_simple->tentative_match = value;
+                 context_simple->tentative_match_len = n_compose;
+
+                 gtk_signal_emit_by_name (GTK_OBJECT (context_simple),
+                                          "preedit-changed");
+
+                 return TRUE;
+               }
+           }
+
+         gtk_im_context_simple_commit_char (GTK_IM_CONTEXT (context_simple), value);
+         context_simple->compose_buffer[0] = 0;
+       }
+      
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+
 static gboolean
 gtk_im_context_simple_filter_keypress (GtkIMContext *context,
                                       GdkEventKey  *event)
 {
   GtkIMContextSimple *context_simple = GTK_IM_CONTEXT_SIMPLE (context);
-  GtkComposeSeq *seq;
+  GSList *tmp_list;
   
   gunichar ch;
   int n_compose = 0;
@@ -840,37 +941,138 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
   context_simple->compose_buffer[n_compose++] = event->keyval;
   context_simple->compose_buffer[n_compose] = 0;
 
-  seq = bsearch (context_simple->compose_buffer,
-                gtk_compose_seqs, G_N_ELEMENTS (gtk_compose_seqs),
-                sizeof (GtkComposeSeq), compare_seq);
+  tmp_list = context_simple->tables;
+  while (tmp_list)
+    {
+      if (check_table (context_simple, tmp_list->data, n_compose))
+       return TRUE;
+      tmp_list = tmp_list->next;
+    }
+  
+  if (check_table (context_simple, &gtk_compose_table, n_compose))
+    return TRUE;
+  
+  /* No compose sequences found, check first if we have a partial
+   * match pending.
+   */
+  if (context_simple->tentative_match)
+    {
+      gint len = context_simple->tentative_match_len;
+      int i;
+      
+      gtk_im_context_simple_commit_char (context, context_simple->tentative_match);
+      context_simple->compose_buffer[0] = 0;
+      
+      for (i=0; i < n_compose - len - 1; i++)
+       {
+         GdkEventKey tmp_event = *event;
+         tmp_event.keyval = context_simple->compose_buffer[len + i];
+         
+         gtk_im_context_filter_keypress (context, &tmp_event);
+       }
 
-  if (seq)
+      return gtk_im_context_filter_keypress (context, event);
+    }
+  else
     {
-      if (n_compose == GTK_MAX_COMPOSE_LEN ||
-         seq->keysyms[n_compose] == 0) /* complete sequence */
+      context_simple->compose_buffer[0] = 0;
+      if (n_compose > 1)               /* Invalid sequence */
        {
-         gtk_im_context_simple_commit_char (context, seq->unicode);
-         context_simple->compose_buffer[0] = 0;
+         gdk_beep();
+         return TRUE;
        }
-      
-      return TRUE;
+  
+      ch = gdk_keyval_to_unicode (event->keyval);
+      if (ch != 0)
+       {
+         gtk_im_context_simple_commit_char (context, ch);
+         return TRUE;
+       }
+      else
+       return FALSE;
     }
+}
 
-  /* No compose sequences found, try simple conversion to unicode
-   */
+static void
+gtk_im_context_simple_reset (GtkIMContext *context)
+{
+  GtkIMContextSimple *context_simple = GTK_IM_CONTEXT_SIMPLE (context);
+  
   context_simple->compose_buffer[0] = 0;
-  if (n_compose > 1)           /* Invalid sequence */
+
+  if (context_simple->tentative_match)
+    gtk_im_context_simple_commit_char (context, context_simple->tentative_match);
+}
+
+static void     
+gtk_im_context_simple_get_preedit_string (GtkIMContext   *context,
+                                         gchar         **str,
+                                         PangoAttrList **attrs,
+                                         gint           *cursor_pos)
+{
+  char outbuf[7];
+  int len = 0;
+
+  GtkIMContextSimple *context_simple = GTK_IM_CONTEXT_SIMPLE (context);
+
+  if (context_simple->tentative_match)
+    len = g_unichar_to_utf8 (context_simple->tentative_match, outbuf);
+
+  if (str)
+    *str = g_strndup (outbuf, len);
+
+  if (attrs)
     {
-      gdk_beep();
-      return TRUE;
+      *attrs = pango_attr_list_new();
+
+      if (len)
+       {
+         PangoAttribute *attr = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE);
+         attr->start_index = 0;
+         attr->end_index = len;
+         pango_attr_list_insert (*attrs, attr);
+       }
     }
+
+  if (cursor_pos)
+    cursor_pos = context_simple->tentative_match ? 1 : 0;
+}
+
+/**
+ * gtk_im_context_simple_add_table:
+ * @context_simple: A #GtkIMContextSimple
+ * @data: the table 
+ * @max_seq_len: Maximum length of a sequence in the table
+ *               (cannot be greater than 7)
+ * @n_seqs: number of sequences in the table
+ * 
+ * Add an additional table to search to the input context.
+ * Each row of the table consists of max_seq_len key symbols
+ * followed by two guint16 interpreted as the high and low
+ * words of a gunicode value. Tables are searched starting
+ * from the last added.
+ *
+ * The table must be sorted in dictionary order on the
+ * by numeric value of the key symbol fields. (Values beyond
+ * the length of the sequence should be zero.)
+ **/
+void
+gtk_im_context_simple_add_table (GtkIMContextSimple *context_simple,
+                                guint16            *data,
+                                gint                max_seq_len,
+                                gint                n_seqs)
+{
+  GtkComposeTable *table;
+
+  g_return_if_fail (GTK_IS_IM_CONTEXT_SIMPLE (context_simple));
+  g_return_if_fail (data != NULL);
+  g_return_if_fail (max_seq_len <= GTK_MAX_COMPOSE_LEN);
   
-  ch = gdk_keyval_to_unicode (event->keyval);
-  if (ch != 0)
-    {
-      gtk_im_context_simple_commit_char (context, ch);
-      return TRUE;
-    }
-  else
-    return FALSE;
+  table = g_new (GtkComposeTable, 1);
+  table->data = data;
+  table->max_seq_len = max_seq_len;
+  table->n_seqs = n_seqs;
+
+  context_simple->tables = g_slist_prepend (context_simple->tables, table);
 }
+
index 80e3b2246b4b1006e12145bf0e6aaaebeb9d5bb5..f166d82b471196038fc9a8d9a42671c9d01fbb4a 100644 (file)
@@ -38,13 +38,17 @@ extern "C" {
 typedef struct _GtkIMContextSimple       GtkIMContextSimple;
 typedef struct _GtkIMContextSimpleClass  GtkIMContextSimpleClass;
 
-#define GTK_MAX_COMPOSE_LEN 4
+#define GTK_MAX_COMPOSE_LEN 7
   
 struct _GtkIMContextSimple
 {
   GtkIMContext object;
+
+  GSList *tables;
   
   guint compose_buffer[GTK_MAX_COMPOSE_LEN + 1];
+  gunichar tentative_match;
+  gint tentative_match_len;
 };
 
 struct _GtkIMContextSimpleClass
@@ -53,8 +57,12 @@ struct _GtkIMContextSimpleClass
 };
 
 GtkType       gtk_im_context_simple_get_type (void) G_GNUC_CONST;
-GtkIMContext *gtk_im_context_simple_new      (void);
+GtkIMContext *gtk_im_context_simple_new       (void);
 
+void          gtk_im_context_simple_add_table (GtkIMContextSimple *context_simple,
+                                              guint16            *data,
+                                              gint                max_seq_len,
+                                              gint                n_seqs);
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
diff --git a/gtk/gtkimmodule.c b/gtk/gtkimmodule.c
new file mode 100644 (file)
index 0000000..3531007
--- /dev/null
@@ -0,0 +1,527 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * Themes added by The Rasterman <raster@redhat.com>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gmodule.h>
+#include <pango/pango-utils.h>
+#include "gtkimmodule.h"
+#include "gtkimcontextsimple.h"
+#include "gtkrc.h"
+#include "config.h"
+#include "gtkintl.h"
+
+#define SIMPLE_ID "gtk-im-context-simple"
+
+typedef struct _GtkIMModule      GtkIMModule;
+typedef struct _GtkIMModuleClass GtkIMModuleClass;
+
+#define GTK_TYPE_IM_MODULE          (gtk_im_module_get_type ())
+#define GTK_IM_MODULE(im_module)    (G_TYPE_CHECK_INSTANCE_CAST ((im_module), GTK_TYPE_IM_MODULE, GtkIMModule))
+#define GTK_IS_IM_MODULE(im_module) (G_TYPE_CHECK_INSTANCE_TYPE ((im_module), GTK_TYPE_IM_MODULE))
+
+struct _GtkIMModule
+{
+  GTypeModule parent_instance;
+  
+  GModule *library;
+
+  void          (*list)   (const GtkIMContextInfo ***contexts,
+                          guint                    *n_contexts);
+  void          (*init)   (GTypeModule              *module);
+  void          (*exit)   (void);
+  GtkIMContext *(*create) (const gchar              *context_id);
+
+  GtkIMContextInfo **contexts;
+  guint n_contexts;
+
+  gchar *path;
+};
+
+struct _GtkIMModuleClass 
+{
+  GTypeModuleClass parent_class;
+};
+
+GType gtk_im_module_get_type (void);
+
+gint n_loaded_contexts = 0;
+static GHashTable *contexts_hash = NULL;
+static GSList *modules_list = NULL;
+
+static GObjectClass *parent_class = NULL;
+
+static gboolean
+gtk_im_module_load (GTypeModule *module)
+{
+  GtkIMModule *im_module = GTK_IM_MODULE (module);
+  
+  im_module->library = g_module_open (im_module->path, 0);
+  if (!im_module->library)
+    {
+      g_warning (g_module_error());
+      return FALSE;
+    }
+  
+  /* extract symbols from the lib */
+  if (!g_module_symbol (im_module->library, "im_module_init",
+                       (gpointer *)&im_module->init) ||
+      !g_module_symbol (im_module->library, "im_module_exit", 
+                       (gpointer *)&im_module->exit) ||
+      !g_module_symbol (im_module->library, "im_module_list", 
+                       (gpointer *)&im_module->list) ||
+      !g_module_symbol (im_module->library, "im_module_create", 
+                       (gpointer *)&im_module->create))
+    {
+      g_warning (g_module_error());
+      g_module_close (im_module->library);
+      
+      return FALSE;
+    }
+           
+  /* call the theme's init (theme_init) function to let it */
+  /* setup anything it needs to set up. */
+  im_module->init (module);
+
+  return TRUE;
+}
+
+static void
+gtk_im_module_unload (GTypeModule *module)
+{
+  GtkIMModule *im_module = GTK_IM_MODULE (module);
+  
+  im_module->exit();
+
+  g_module_close (im_module->library);
+  im_module->library = NULL;
+
+  im_module->init = NULL;
+  im_module->exit = NULL;
+  im_module->list = NULL;
+  im_module->create = NULL;
+}
+
+/* This only will ever be called if an error occurs during
+ * initialization
+ */
+static void
+gtk_im_module_finalize (GObject *object)
+{
+  GtkIMModule *module = GTK_IM_MODULE (object);
+
+  g_free (module->path);
+
+  parent_class->finalize (object);
+}
+
+static void
+gtk_im_module_class_init (GtkIMModuleClass *class)
+{
+  GTypeModuleClass *module_class = G_TYPE_MODULE_CLASS (class);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+
+  parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (class));
+  
+  module_class->load = gtk_im_module_load;
+  module_class->unload = gtk_im_module_unload;
+
+  gobject_class->finalize = gtk_im_module_finalize;
+}
+
+GType
+gtk_im_module_get_type (void)
+{
+  static GType im_module_type = 0;
+
+  if (!im_module_type)
+    {
+      static const GTypeInfo im_module_info = {
+        sizeof (GtkIMModuleClass),
+        NULL,           /* base_init */
+        NULL,           /* base_finalize */
+        (GClassInitFunc) gtk_im_module_class_init,
+        NULL,           /* class_finalize */
+        NULL,           /* class_data */
+        sizeof (GtkIMModule),
+        0,              /* n_preallocs */
+        NULL,           /* instance_init */
+      };
+
+      im_module_type = g_type_register_static (G_TYPE_TYPE_MODULE, "GtkIMModule", &im_module_info, 0);
+    }
+  
+  return im_module_type;
+}
+
+static void
+free_info (GtkIMContextInfo *info)
+{
+  g_free ((char *)info->context_id);
+  g_free ((char *)info->context_name);
+  g_free ((char *)info->domain);
+  g_free ((char *)info->domain_dirname);
+  g_free ((char *)info->default_locales);
+  g_free (info);
+}
+
+static void
+add_module (GtkIMModule *module, GSList *infos)
+{
+  GSList *tmp_list = infos;
+  gint i = 0;
+  gint n = g_slist_length (infos);
+  module->contexts = g_new (GtkIMContextInfo *, n);
+
+  while (tmp_list)
+    {
+      GtkIMContextInfo *info = tmp_list->data;
+  
+      if (g_hash_table_lookup (contexts_hash, info->context_id))
+       {
+         free_info (info);     /* Duplicate */
+       }
+      else
+       {
+         g_hash_table_insert (contexts_hash, (char *)info->context_id, module);
+         module->contexts[i++] = tmp_list->data;
+         n_loaded_contexts++;
+       }
+      
+      tmp_list = tmp_list->next;
+    }
+  g_slist_free (infos);
+  module->n_contexts = i;
+
+  modules_list = g_slist_prepend (modules_list, module);
+}
+
+static void
+gtk_im_module_init ()
+{
+  GString *line_buf = g_string_new (NULL);
+  GString *tmp_buf = g_string_new (NULL);
+  const gchar *filename = gtk_rc_get_im_module_file();
+  FILE *file;
+  gboolean have_error = FALSE;
+
+  GtkIMModule *module = NULL;
+  GSList *infos = NULL;
+
+  contexts_hash = g_hash_table_new (g_str_hash, g_str_equal);
+
+  file = fopen (filename, "r");
+  if (!file)
+    {
+      g_warning ("Can not open Input Method module file '%s': %s",
+                filename, g_strerror (errno));
+      return;
+    }
+
+  while (!have_error && pango_read_line (file, line_buf))
+    {
+      const char *p;
+      
+      p = line_buf->str;
+
+      if (!pango_skip_space (&p))
+       {
+         /* Blank line marking the end of a module
+          */
+         if (module && *p != '#')
+           {
+             add_module (module, infos);
+             module = NULL;
+             infos = NULL;
+           }
+         
+         continue;
+       }
+
+      if (!module)
+       {
+         /* Read a module location
+          */
+         module = g_object_new (GTK_TYPE_IM_MODULE, NULL);
+
+         if (!pango_scan_string (&p, tmp_buf) ||
+             pango_skip_space (&p))
+           {
+             g_warning ("Error parsing context info in '%s'\n  %s", 
+                        filename, line_buf->str);
+             have_error = TRUE;
+           }
+
+         module->path = g_strdup (tmp_buf->str);
+         g_type_module_set_name (G_TYPE_MODULE (module), module->path);
+       }
+      else
+       {
+         GtkIMContextInfo *info = g_new0 (GtkIMContextInfo, 1);
+         
+         /* Read information about a context type
+          */
+         if (!pango_scan_string (&p, tmp_buf))
+           goto context_error;
+         info->context_id = g_strdup (tmp_buf->str);
+
+         if (!pango_scan_string (&p, tmp_buf))
+           goto context_error;
+         info->context_name = g_strdup (tmp_buf->str);
+
+         if (!pango_scan_string (&p, tmp_buf))
+           goto context_error;
+         info->domain = g_strdup (tmp_buf->str);
+
+         if (!pango_scan_string (&p, tmp_buf))
+           goto context_error;
+         info->domain_dirname = g_strdup (tmp_buf->str);
+
+         if (!pango_scan_string (&p, tmp_buf))
+           goto context_error;
+         info->default_locales = g_strdup (tmp_buf->str);
+
+         if (pango_skip_space (&p))
+           goto context_error;
+
+         infos = g_slist_prepend (infos, info);
+         continue;
+
+       context_error:
+         g_warning ("Error parsing context info in '%s'\n  %s", 
+                    filename, line_buf->str);
+         have_error = TRUE;
+       }
+    }
+
+  if (have_error)
+    {
+      GSList *tmp_list = infos;
+      while (tmp_list)
+       {
+         free_info (tmp_list->data);
+         tmp_list = tmp_list->next;
+       }
+      g_slist_free (infos);
+
+      g_object_unref (G_OBJECT (module));
+    }
+  else if (module)
+    add_module (module, infos);
+
+  fclose (file);
+  g_string_free (line_buf, TRUE);
+  g_string_free (tmp_buf, TRUE);
+}
+
+/**
+ * _gtk_im_module_list:
+ * @contexts: location to store an array of pointers to #GtkIMContextInfo
+ *            this array should be freed with g_free() when you are finished.
+ *            The structures it points are statically allocated and should
+ *            not be modified or freed.
+ * @n_contexts: the length of the array stored in @contexts
+ * 
+ * List all available types of input method context
+ **/
+void
+_gtk_im_module_list (const GtkIMContextInfo ***contexts,
+                    guint                    *n_contexts)
+{
+  int n = 0;
+
+  static const GtkIMContextInfo simple_context_info = {
+    SIMPLE_ID,
+    "Default",
+    "gtk+",
+    NULL,
+    ""
+  };
+
+  if (!contexts_hash)
+    gtk_im_module_init ();
+
+  if (n_contexts)
+    *n_contexts = (n_loaded_contexts + 1);
+
+  if (contexts)
+    {
+      GSList *tmp_list;
+      int i;
+      
+      *contexts = g_new (const GtkIMContextInfo *, n_loaded_contexts + 1);
+
+      (*contexts)[n++] = &simple_context_info;
+
+      tmp_list = modules_list;
+      while (tmp_list)
+       {
+         GtkIMModule *module = tmp_list->data;
+
+         for (i=0; i<module->n_contexts; i++)
+           (*contexts)[n++] = module->contexts[i];
+         
+         tmp_list = tmp_list->next;
+       }
+    }
+}
+
+/**
+ * _gtk_im_module_create:
+ * @context_id: the context ID for the context type to create
+ * 
+ * Create an IM context of a type specified by the string
+ * ID @context_id.
+ * 
+ * Return value: a newly created input context of or @context_id, or
+ * if that could not be created, a newly created GtkIMContextSimple.
+ **/
+GtkIMContext *
+_gtk_im_module_create (const gchar *context_id)
+{
+  GtkIMModule *im_module;
+  GtkIMContext *context = NULL;
+  
+  if (!contexts_hash)
+    gtk_im_module_init ();
+
+  if (strcmp (context_id, SIMPLE_ID) != 0)
+    {
+      im_module = g_hash_table_lookup (contexts_hash, context_id);
+      if (!im_module)
+       {
+         g_warning ("Attempt to load unknown IM context type '%s'", context_id);
+       }
+      else
+       {
+         if (g_type_module_use (G_TYPE_MODULE (im_module)))
+           {
+             context = im_module->create (context_id);
+             g_type_module_unuse (G_TYPE_MODULE (im_module));
+           }
+         
+         if (!context)
+           g_warning ("Loading IM context type '%s' failed", context_id);
+       }
+    }
+  
+  if (!context)
+     return gtk_im_context_simple_new ();
+  else
+    return context;
+}
+
+/* Match @locale against @against.
+ * 
+ * 'en_US' against 'en_US'       => 3
+ * 'en_US' against 'en'          => 2
+ * 'en', 'en_UK' against 'en_US' => 1
+ */
+static gint
+match_locale (const gchar *locale,
+             const gchar *against,
+             gint         against_len)
+{
+  if (strcmp (locale, against) == 0)
+    return 3;
+
+  if (strncmp (locale, against, 2) == 0)
+    return (against_len == 2) ? 2 : 1;
+
+  return 0;
+}
+
+/**
+ * _gtk_im_module_get_default_context_id:
+ * @locale: a locale id in the form 'en_US'
+ * 
+ * Return the context_id of the best IM context type
+ * for the given locale ID.
+ * 
+ * Return value: the context ID (will never be %NULL)
+ *    the value is newly allocated and must be freed
+ *    with g_free().
+ **/
+const gchar *
+_gtk_im_module_get_default_context_id (const gchar *locale)
+{
+  GSList *tmp_list;
+  const gchar *context_id = NULL;
+  gint best_goodness = 0;
+  gint i;
+  gchar *tmp_locale, *tmp;
+  gchar *envvar;
+      
+  if (!contexts_hash)
+    gtk_im_module_init ();
+
+  envvar = g_getenv ("GTK_IM_MODULE");
+  if (envvar && g_hash_table_lookup (contexts_hash, envvar))
+    return g_strdup (envvar);
+
+  /* Strip the locale code down to the essentials
+   */
+  tmp_locale = g_strdup (locale);
+  tmp = strchr (tmp_locale, '.');
+  if (tmp)
+    *tmp = '\0';
+  tmp = strchr (tmp_locale, '@');
+  if (tmp)
+    *tmp = '\0';
+  
+  tmp_list = modules_list;
+  while (tmp_list)
+    {
+      GtkIMModule *module = tmp_list->data;
+     
+      for (i=0; i<module->n_contexts; i++)
+       {
+         const gchar *p = module->contexts[i]->default_locales;
+         while (p)
+           {
+             const gchar *q = strchr (p, ':');
+             gint goodness = match_locale (tmp_locale, p, q ? q - p : strlen (p));
+
+             if (goodness > best_goodness)
+               {
+                 context_id = module->contexts[i]->context_id;
+                 best_goodness = goodness;
+               }
+
+             p = q ? q + 1 : NULL;
+           }
+       }
+      
+      tmp_list = tmp_list->next;
+    }
+
+  g_free (tmp_locale);
+  
+  return g_strdup (context_id ? context_id : SIMPLE_ID);
+}
diff --git a/gtk/gtkimmodule.h b/gtk/gtkimmodule.h
new file mode 100644 (file)
index 0000000..d9ce11b
--- /dev/null
@@ -0,0 +1,62 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2000 Red Hat Software
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_IM_MODULE_H__
+#define __GTK_IM_MODULE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include <gtk/gtkimcontext.h>
+
+typedef struct _GtkIMContextInfo GtkIMContextInfo;
+
+struct _GtkIMContextInfo 
+{
+  const gchar *context_id;
+  const gchar *context_name;
+  const gchar *domain;
+  const gchar *domain_dirname;
+  const gchar *default_locales;
+};
+
+/* Functions for use within GTK+
+ */
+void          _gtk_im_module_list                   (const GtkIMContextInfo ***contexts,
+                                                   guint                    *n_contexts);
+GtkIMContext *_gtk_im_module_create                 (const gchar             *context_id);
+const gchar * _gtk_im_module_get_default_context_id (const gchar             *lang);
+
+/* The following entry points are exported by each input method module
+ */
+
+/*
+void          im_module_list   (const GtkIMContextInfo ***contexts,
+                               guint                    *n_contexts);
+void          im_module_init   (GtkModule             *module);
+void          im_module_exit   (void);
+GtkIMContext *im_module_create (const gchar             *context_id);
+*/
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif __GTK_IM_MODULE_H__
index 58b8296a1815fea379b8455e9bccfb880bc787a9..2ec808356fc8b4b77e353dd6d8f46e0b6a111a13 100644 (file)
  * Boston, MA 02111-1307, USA.
  */
 
+#include <string.h>
+
+#ifdef GDK_WINDOWING_X11
+#include <X11/Xlocale.h>       /* so we get the right setlocale */
+#else
+#include <locale.h>
+#endif
+
 #include "gtksignal.h"
 #include "gtkimmulticontext.h"
-#include "gtkimcontextsimple.h"
+#include "gtkimmodule.h"
+#include "gtkmenuitem.h"
 
 static void     gtk_im_multicontext_class_init         (GtkIMMulticontextClass  *class);
 static void     gtk_im_multicontext_init               (GtkIMMulticontext       *im_multicontext);
@@ -32,11 +41,13 @@ static void     gtk_im_multicontext_set_client_window  (GtkIMContext
                                                        GdkWindow               *window);
 static void     gtk_im_multicontext_get_preedit_string (GtkIMContext            *context,
                                                        gchar                  **str,
-                                                       PangoAttrList          **attrs);
+                                                       PangoAttrList          **attrs,
+                                                       gint                   *cursor_pos);
 static gboolean gtk_im_multicontext_filter_keypress    (GtkIMContext            *context,
                                                        GdkEventKey             *event);
 static void     gtk_im_multicontext_focus_in           (GtkIMContext            *context);
 static void     gtk_im_multicontext_focus_out          (GtkIMContext            *context);
+static void     gtk_im_multicontext_reset              (GtkIMContext            *context);
 
 void            gtk_im_multicontext_preedit_start_cb   (GtkIMContext            *slave,
                                                        GtkIMMulticontext       *multicontext);
@@ -50,6 +61,8 @@ void            gtk_im_multicontext_commit_cb          (GtkIMContext
 
 static GtkIMContextClass *parent_class;
 
+static const gchar *global_context_id = NULL;
+
 GtkType
 gtk_im_multicontext_get_type (void)
 {
@@ -88,6 +101,7 @@ gtk_im_multicontext_class_init (GtkIMMulticontextClass *class)
   im_context_class->filter_keypress = gtk_im_multicontext_filter_keypress;
   im_context_class->focus_in = gtk_im_multicontext_focus_in;
   im_context_class->focus_out = gtk_im_multicontext_focus_out;
+  im_context_class->reset = gtk_im_multicontext_reset;
 
   gobject_class->finalize = gtk_im_multicontext_finalize;
 }
@@ -141,6 +155,9 @@ gtk_im_multicontext_set_slave (GtkIMMulticontext *multicontext,
       gtk_signal_connect (GTK_OBJECT (multicontext->slave), "commit",
                          GTK_SIGNAL_FUNC (gtk_im_multicontext_commit_cb),
                          multicontext);
+
+      if (multicontext->client_window)
+       gtk_im_context_set_client_window (slave, multicontext->client_window);
     }
 }
 
@@ -148,7 +165,22 @@ static GtkIMContext *
 gtk_im_multicontext_get_slave (GtkIMMulticontext *multicontext)
 {
   if (!multicontext->slave)
-    gtk_im_multicontext_set_slave (multicontext, gtk_im_context_simple_new ());
+    {
+      if (!global_context_id)
+       {
+         const char *locale;
+         
+#ifdef HAVE_LC_MESSAGES
+         locale = setlocale (LC_MESSAGES, NULL);
+#else
+         locale = setlocale (LC_CTYPE, NULL);
+#endif
+         global_context_id = _gtk_im_module_get_default_context_id (locale);
+       }
+       
+      gtk_im_multicontext_set_slave (multicontext, _gtk_im_module_create (global_context_id));
+      multicontext->context_id = global_context_id;
+    }
 
   return multicontext->slave;
 }
@@ -160,6 +192,8 @@ gtk_im_multicontext_set_client_window (GtkIMContext *context,
   GtkIMMulticontext *multicontext = GTK_IM_MULTICONTEXT (context);
   GtkIMContext *slave = gtk_im_multicontext_get_slave (multicontext);
 
+  multicontext->client_window = window;
+  
   if (slave)
     gtk_im_context_set_client_window (slave, window);
 }
@@ -167,13 +201,14 @@ gtk_im_multicontext_set_client_window (GtkIMContext *context,
 static void
 gtk_im_multicontext_get_preedit_string (GtkIMContext   *context,
                                        gchar         **str,
-                                       PangoAttrList **attrs)
+                                       PangoAttrList **attrs,
+                                       gint           *cursor_pos)
 {
   GtkIMMulticontext *multicontext = GTK_IM_MULTICONTEXT (context);
   GtkIMContext *slave = gtk_im_multicontext_get_slave (multicontext);
 
   if (slave)
-    gtk_im_context_get_preedit_string (slave, str, attrs);
+    gtk_im_context_get_preedit_string (slave, str, attrs, cursor_pos);
   else
     {
       if (str)
@@ -200,7 +235,17 @@ static void
 gtk_im_multicontext_focus_in (GtkIMContext   *context)
 {
   GtkIMMulticontext *multicontext = GTK_IM_MULTICONTEXT (context);
-  GtkIMContext *slave = gtk_im_multicontext_get_slave (multicontext);
+  GtkIMContext *slave;
+
+  /* If the global context type is different from the context we were
+   * using before, get rid of the old slave and create a new one
+   * for the new global context type.
+   */
+  if (!multicontext->context_id ||
+      strcmp (global_context_id, multicontext->context_id) != 0)
+    gtk_im_multicontext_set_slave (multicontext, NULL);
+
+  slave = gtk_im_multicontext_get_slave (multicontext);
 
   if (slave)
     gtk_im_context_focus_in (slave);
@@ -216,6 +261,16 @@ gtk_im_multicontext_focus_out (GtkIMContext   *context)
     gtk_im_context_focus_out (slave);
 }
 
+static void
+gtk_im_multicontext_reset (GtkIMContext   *context)
+{
+  GtkIMMulticontext *multicontext = GTK_IM_MULTICONTEXT (context);
+  GtkIMContext *slave = gtk_im_multicontext_get_slave (multicontext);
+
+  if (slave)
+    gtk_im_context_reset (slave);
+}
+
 void
 gtk_im_multicontext_preedit_start_cb   (GtkIMContext      *slave,
                                        GtkIMMulticontext *multicontext)
@@ -245,3 +300,49 @@ gtk_im_multicontext_commit_cb (GtkIMContext      *slave,
   gtk_signal_emit_by_name (GTK_OBJECT (multicontext), "commit", str);;
 }
 
+static void
+activate_cb (GtkWidget         *menuitem,
+            GtkIMMulticontext *context)
+{
+  const gchar *id = gtk_object_get_data (GTK_OBJECT (menuitem), "gtk-context-id");
+
+  gtk_im_context_reset (GTK_IM_CONTEXT (context));
+
+  global_context_id = id;
+  gtk_im_multicontext_set_slave (context, NULL);
+}
+
+/**
+ * gtk_im_multicontext_append_menuitems:
+ * @context: a #GtkIMMultiContext
+ * @menushell: a #GtkMenuShell
+ * 
+ * Add menuitems for various available input methods to a menu;
+ * the menuitems, when selected, will switch the input method
+ * for the context and the global default input method.
+ **/
+void
+gtk_im_multicontext_append_menuitems (GtkIMMulticontext *context,
+                                     GtkMenuShell      *menushell)
+{
+  const GtkIMContextInfo **contexts;
+  gint n_contexts, i;
+  
+  _gtk_im_module_list (&contexts, &n_contexts);
+
+  for (i=0; i < n_contexts; i++)
+    {
+      GtkWidget *menuitem;
+
+      menuitem = gtk_menu_item_new_with_label (contexts[i]->context_name);
+
+      gtk_object_set_data (GTK_OBJECT (menuitem), "gtk-context-id",
+                          (char *)contexts[i]->context_id);
+      gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
+                         activate_cb, context);
+
+      gtk_widget_show (menuitem);
+      gtk_menu_shell_append (menushell, menuitem);
+    }
+}
+
index bed52f01d770f674410717152e11ff1847dfe3c7..faa8b294d5dd30034d1406e03c87546934d03598 100644 (file)
@@ -21,6 +21,7 @@
 #define __GTK_IM_MULTICONTEXT_H__
 
 #include <gtk/gtkimcontext.h>
+#include <gtk/gtkmenushell.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -43,6 +44,10 @@ struct _GtkIMMulticontext
   GtkIMContext object;
 
   GtkIMContext *slave;
+
+  GdkWindow *client_window;
+
+  const gchar *context_id;
 };
 
 struct _GtkIMMulticontextClass
@@ -53,6 +58,9 @@ struct _GtkIMMulticontextClass
 GtkType       gtk_im_multicontext_get_type (void) G_GNUC_CONST;
 GtkIMContext *gtk_im_multicontext_new      (void);
 
+void          gtk_im_multicontext_append_menuitems (GtkIMMulticontext *context,
+                                                   GtkMenuShell      *menushell);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
diff --git a/gtk/gtkoldeditable.c b/gtk/gtkoldeditable.c
new file mode 100644 (file)
index 0000000..a085d06
--- /dev/null
@@ -0,0 +1,859 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include <ctype.h>
+#include <string.h>
+#include "gdk/gdkkeysyms.h"
+#include "gdk/gdki18n.h"
+#include "gtkclipboard.h"
+#include "gtkoldeditable.h"
+#include "gtkmain.h"
+#include "gtkselection.h"
+#include "gtksignal.h"
+
+#define MIN_EDITABLE_WIDTH  150
+#define DRAW_TIMEOUT     20
+#define INNER_BORDER     2
+
+enum {
+  CHANGED,
+  INSERT_TEXT,
+  DELETE_TEXT,
+  /* Binding actions */
+  ACTIVATE,
+  SET_EDITABLE,
+  MOVE_CURSOR,
+  MOVE_WORD,
+  MOVE_PAGE,
+  MOVE_TO_ROW,
+  MOVE_TO_COLUMN,
+  KILL_CHAR,
+  KILL_WORD,
+  KILL_LINE,
+  CUT_CLIPBOARD,
+  COPY_CLIPBOARD,
+  PASTE_CLIPBOARD,
+  LAST_SIGNAL
+};
+
+enum {
+  ARG_0,
+  ARG_TEXT_POSITION,
+  ARG_EDITABLE
+};
+
+/* values for selection info */
+
+enum {
+  TARGET_STRING,
+  TARGET_TEXT,
+  TARGET_COMPOUND_TEXT
+};
+
+static void  gtk_old_editable_class_init           (GtkOldEditableClass *klass);
+static void  gtk_old_editable_editable_init        (GtkEditableClass    *iface);
+static void  gtk_old_editable_init                 (GtkOldEditable      *editable);
+static void  gtk_old_editable_set_arg              (GtkObject           *object,
+                                                   GtkArg              *arg,
+                                                   guint                arg_id);
+static void  gtk_old_editable_get_arg              (GtkObject           *object,
+                                                   GtkArg              *arg,
+                                                   guint                arg_id);
+static void *gtk_old_editable_get_public_chars     (GtkOldEditable      *old_editable,
+                                                   gint                 start,
+                                                   gint                 end);
+
+static gint gtk_old_editable_selection_clear    (GtkWidget         *widget,
+                                                GdkEventSelection *event);
+static void gtk_old_editable_selection_get      (GtkWidget         *widget,
+                                                GtkSelectionData  *selection_data,
+                                                guint              info,
+                                                guint              time);
+static void gtk_old_editable_selection_received (GtkWidget         *widget,
+                                                GtkSelectionData  *selection_data,
+                                                guint              time);
+
+static void  gtk_old_editable_set_selection        (GtkOldEditable      *old_editable,
+                                                   gint                 start,
+                                                   gint                 end);
+
+static void gtk_old_editable_real_set_editable    (GtkOldEditable *old_editable,
+                                                  gboolean        is_editable);
+static void gtk_old_editable_real_cut_clipboard   (GtkOldEditable *old_editable);
+static void gtk_old_editable_real_copy_clipboard  (GtkOldEditable *old_editable);
+static void gtk_old_editable_real_paste_clipboard (GtkOldEditable *old_editable);
+
+static void     gtk_old_editable_insert_text         (GtkEditable *editable,
+                                                     const gchar *new_text,
+                                                     gint         new_text_length,
+                                                     gint        *position);
+static void     gtk_old_editable_delete_text         (GtkEditable *editable,
+                                                     gint         start_pos,
+                                                     gint         end_pos);
+static gchar *  gtk_old_editable_get_chars           (GtkEditable *editable,
+                                                     gint         start,
+                                                     gint         end);
+static void     gtk_old_editable_set_selection_bounds (GtkEditable *editable,
+                                                      gint         start,
+                                                      gint         end);
+static gboolean gtk_old_editable_get_selection_bounds (GtkEditable *editable,
+                                                      gint        *start,
+                                                      gint        *end);
+static void     gtk_old_editable_set_position        (GtkEditable *editable,
+                                                     gint         position);
+static gint     gtk_old_editable_get_position        (GtkEditable *editable);
+
+static GtkWidgetClass *parent_class = NULL;
+static guint editable_signals[LAST_SIGNAL] = { 0 };
+
+GtkType
+gtk_old_editable_get_type (void)
+{
+  static GtkType old_editable_type = 0;
+
+  if (!old_editable_type)
+    {
+      static const GtkTypeInfo old_editable_info =
+      {
+       "GtkOldEditable",
+       sizeof (GtkOldEditable),
+       sizeof (GtkOldEditableClass),
+       (GtkClassInitFunc) gtk_old_editable_class_init,
+       (GtkObjectInitFunc) gtk_old_editable_init,
+       /* reserved_1 */ NULL,
+       /* reserved_2 */ NULL,
+        (GtkClassInitFunc) NULL,
+      };
+
+      static const GInterfaceInfo editable_info =
+      {
+       (GInterfaceInitFunc) gtk_old_editable_editable_init,     /* interface_init */
+       NULL,                                                    /* interface_finalize */
+       NULL                                                     /* interface_data */
+      };
+
+      old_editable_type = gtk_type_unique (GTK_TYPE_WIDGET, &old_editable_info);
+      g_type_add_interface_static (old_editable_type,
+                                  GTK_TYPE_EDITABLE,
+                                  &editable_info);
+    }
+
+  return old_editable_type;
+}
+
+static void
+gtk_old_editable_class_init (GtkOldEditableClass *class)
+{
+  GtkObjectClass *object_class;
+  GtkWidgetClass *widget_class;
+
+  object_class = (GtkObjectClass*) class;
+  widget_class = (GtkWidgetClass*) class;
+
+  parent_class = gtk_type_class (GTK_TYPE_WIDGET);
+
+  editable_signals[CHANGED] =
+    gtk_signal_new ("changed",
+                   GTK_RUN_LAST,
+                   GTK_CLASS_TYPE (object_class),
+                   GTK_SIGNAL_OFFSET (GtkOldEditableClass, changed),
+                   gtk_marshal_NONE__NONE,
+                   GTK_TYPE_NONE, 0);
+
+  editable_signals[INSERT_TEXT] =
+    gtk_signal_new ("insert_text",
+                   GTK_RUN_LAST,
+                   GTK_CLASS_TYPE (object_class),
+                   GTK_SIGNAL_OFFSET (GtkOldEditableClass, insert_text),
+                   gtk_marshal_NONE__POINTER_INT_POINTER,
+                   GTK_TYPE_NONE,
+                   3,
+                   GTK_TYPE_STRING,
+                   GTK_TYPE_INT,
+                   GTK_TYPE_POINTER);
+
+  editable_signals[DELETE_TEXT] =
+    gtk_signal_new ("delete_text",
+                   GTK_RUN_LAST,
+                   GTK_CLASS_TYPE (object_class),
+                   GTK_SIGNAL_OFFSET (GtkOldEditableClass, delete_text),
+                   gtk_marshal_NONE__INT_INT,
+                   GTK_TYPE_NONE,
+                   2,
+                   GTK_TYPE_INT,
+                   GTK_TYPE_INT);                  
+
+  editable_signals[ACTIVATE] =
+    gtk_signal_new ("activate",
+                   GTK_RUN_LAST | GTK_RUN_ACTION,
+                   GTK_CLASS_TYPE (object_class),
+                   GTK_SIGNAL_OFFSET (GtkOldEditableClass, activate),
+                   gtk_marshal_NONE__NONE,
+                   GTK_TYPE_NONE, 0);
+  widget_class->activate_signal = editable_signals[ACTIVATE];
+
+  editable_signals[SET_EDITABLE] =
+    gtk_signal_new ("set-editable",
+                   GTK_RUN_LAST | GTK_RUN_ACTION,
+                   GTK_CLASS_TYPE (object_class),
+                   GTK_SIGNAL_OFFSET (GtkOldEditableClass, set_editable),
+                   gtk_marshal_NONE__BOOL,
+                   GTK_TYPE_NONE, 1,
+                   GTK_TYPE_BOOL);
+
+  editable_signals[MOVE_CURSOR] =
+    gtk_signal_new ("move_cursor",
+                   GTK_RUN_LAST | GTK_RUN_ACTION,
+                   GTK_CLASS_TYPE (object_class),
+                   GTK_SIGNAL_OFFSET (GtkOldEditableClass, move_cursor),
+                   gtk_marshal_NONE__INT_INT,
+                   GTK_TYPE_NONE, 2, 
+                   GTK_TYPE_INT, 
+                   GTK_TYPE_INT);
+
+  editable_signals[MOVE_WORD] =
+    gtk_signal_new ("move_word",
+                   GTK_RUN_LAST | GTK_RUN_ACTION,
+                   GTK_CLASS_TYPE (object_class),
+                   GTK_SIGNAL_OFFSET (GtkOldEditableClass, move_word),
+                   gtk_marshal_NONE__INT,
+                   GTK_TYPE_NONE, 1, 
+                   GTK_TYPE_INT);
+
+  editable_signals[MOVE_PAGE] =
+    gtk_signal_new ("move_page",
+                   GTK_RUN_LAST | GTK_RUN_ACTION,
+                   GTK_CLASS_TYPE (object_class),
+                   GTK_SIGNAL_OFFSET (GtkOldEditableClass, move_page),
+                   gtk_marshal_NONE__INT_INT,
+                   GTK_TYPE_NONE, 2, 
+                   GTK_TYPE_INT, 
+                   GTK_TYPE_INT);
+
+  editable_signals[MOVE_TO_ROW] =
+    gtk_signal_new ("move_to_row",
+                   GTK_RUN_LAST | GTK_RUN_ACTION,
+                   GTK_CLASS_TYPE (object_class),
+                   GTK_SIGNAL_OFFSET (GtkOldEditableClass, move_to_row),
+                   gtk_marshal_NONE__INT,
+                   GTK_TYPE_NONE, 1, 
+                   GTK_TYPE_INT);
+
+  editable_signals[MOVE_TO_COLUMN] =
+    gtk_signal_new ("move_to_column",
+                   GTK_RUN_LAST | GTK_RUN_ACTION,
+                   GTK_CLASS_TYPE (object_class),
+                   GTK_SIGNAL_OFFSET (GtkOldEditableClass, move_to_column),
+                   gtk_marshal_NONE__INT,
+                   GTK_TYPE_NONE, 1, 
+                   GTK_TYPE_INT);
+
+  editable_signals[KILL_CHAR] =
+    gtk_signal_new ("kill_char",
+                   GTK_RUN_LAST | GTK_RUN_ACTION,
+                   GTK_CLASS_TYPE (object_class),
+                   GTK_SIGNAL_OFFSET (GtkOldEditableClass, kill_char),
+                   gtk_marshal_NONE__INT,
+                   GTK_TYPE_NONE, 1, 
+                   GTK_TYPE_INT);
+
+  editable_signals[KILL_WORD] =
+    gtk_signal_new ("kill_word",
+                   GTK_RUN_LAST | GTK_RUN_ACTION,
+                   GTK_CLASS_TYPE (object_class),
+                   GTK_SIGNAL_OFFSET (GtkOldEditableClass, kill_word),
+                   gtk_marshal_NONE__INT,
+                   GTK_TYPE_NONE, 1, 
+                   GTK_TYPE_INT);
+
+  editable_signals[KILL_LINE] =
+    gtk_signal_new ("kill_line",
+                   GTK_RUN_LAST | GTK_RUN_ACTION,
+                   GTK_CLASS_TYPE (object_class),
+                   GTK_SIGNAL_OFFSET (GtkOldEditableClass, kill_line),
+                   gtk_marshal_NONE__INT,
+                   GTK_TYPE_NONE, 1, 
+                   GTK_TYPE_INT);
+
+  editable_signals[CUT_CLIPBOARD] =
+    gtk_signal_new ("cut_clipboard",
+                   GTK_RUN_LAST | GTK_RUN_ACTION,
+                   GTK_CLASS_TYPE (object_class),
+                   GTK_SIGNAL_OFFSET (GtkOldEditableClass, cut_clipboard),
+                   gtk_marshal_NONE__NONE,
+                   GTK_TYPE_NONE, 0);
+
+  editable_signals[COPY_CLIPBOARD] =
+    gtk_signal_new ("copy_clipboard",
+                   GTK_RUN_LAST | GTK_RUN_ACTION,
+                   GTK_CLASS_TYPE (object_class),
+                   GTK_SIGNAL_OFFSET (GtkOldEditableClass, copy_clipboard),
+                   gtk_marshal_NONE__NONE,
+                   GTK_TYPE_NONE, 0);
+
+  editable_signals[PASTE_CLIPBOARD] =
+    gtk_signal_new ("paste_clipboard",
+                   GTK_RUN_LAST | GTK_RUN_ACTION,
+                   GTK_CLASS_TYPE (object_class),
+                   GTK_SIGNAL_OFFSET (GtkOldEditableClass, paste_clipboard),
+                   gtk_marshal_NONE__NONE,
+                   GTK_TYPE_NONE, 0);
+
+  gtk_object_class_add_signals (object_class, editable_signals, LAST_SIGNAL);
+
+  gtk_object_add_arg_type ("GtkOldEditable::text_position", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_TEXT_POSITION);
+  gtk_object_add_arg_type ("GtkOldEditable::editable", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_EDITABLE);
+    
+  object_class->set_arg = gtk_old_editable_set_arg;
+  object_class->get_arg = gtk_old_editable_get_arg;
+
+  widget_class->selection_clear_event = gtk_old_editable_selection_clear;
+  widget_class->selection_received = gtk_old_editable_selection_received;
+  widget_class->selection_get = gtk_old_editable_selection_get;
+
+  class->insert_text = NULL;
+  class->delete_text = NULL;
+
+  class->activate = NULL;
+  class->set_editable = gtk_old_editable_real_set_editable;
+
+  class->move_cursor = NULL;
+  class->move_word = NULL;
+  class->move_page = NULL;
+  class->move_to_row = NULL;
+  class->move_to_column = NULL;
+
+  class->kill_char = NULL;
+  class->kill_word = NULL;
+  class->kill_line = NULL;
+
+  class->cut_clipboard = gtk_old_editable_real_cut_clipboard;
+  class->copy_clipboard = gtk_old_editable_real_copy_clipboard;
+  class->paste_clipboard = gtk_old_editable_real_paste_clipboard;
+
+  class->update_text = NULL;
+  class->get_chars = NULL;
+  class->set_selection = NULL;
+  class->set_position = NULL;
+}
+
+static void
+gtk_old_editable_editable_init (GtkEditableClass *iface)
+{
+  iface->insert_text = gtk_old_editable_insert_text;
+  iface->delete_text = gtk_old_editable_delete_text;
+  iface->get_chars = gtk_old_editable_get_chars;
+  iface->set_selection_bounds = gtk_old_editable_set_selection_bounds;
+  iface->get_selection_bounds = gtk_old_editable_get_selection_bounds;
+  iface->set_position = gtk_old_editable_set_position;
+  iface->get_position = gtk_old_editable_get_position;
+}
+
+static void
+gtk_old_editable_set_arg (GtkObject *object,
+                         GtkArg    *arg,
+                         guint      arg_id)
+{
+  GtkEditable *editable = GTK_EDITABLE (object);
+
+  switch (arg_id)
+    {
+    case ARG_TEXT_POSITION:
+      gtk_editable_set_position (editable, GTK_VALUE_INT (*arg));
+      break;
+    case ARG_EDITABLE:
+      gtk_signal_emit (object, editable_signals[SET_EDITABLE],
+                      GTK_VALUE_BOOL (*arg) != FALSE);
+      break;
+    default:
+      break;
+    }
+}
+
+static void
+gtk_old_editable_get_arg (GtkObject *object,
+                         GtkArg    *arg,
+                         guint      arg_id)
+{
+  GtkOldEditable *old_editable;
+
+  old_editable = GTK_OLD_EDITABLE (object);
+
+  switch (arg_id)
+    {
+    case ARG_TEXT_POSITION:
+      GTK_VALUE_INT (*arg) = old_editable->current_pos;
+      break;
+    case ARG_EDITABLE:
+      GTK_VALUE_BOOL (*arg) = old_editable->editable;
+      break;
+    default:
+      arg->type = GTK_TYPE_INVALID;
+      break;
+    }
+}
+
+static void
+gtk_old_editable_init (GtkOldEditable *old_editable)
+{
+  static const GtkTargetEntry targets[] = {
+    { "UTF8_STRING", 0, 0 },
+    { "STRING", 0, 0 },
+    { "TEXT",   0, 0 }, 
+    { "COMPOUND_TEXT", 0, 0 }
+  };
+
+  GTK_WIDGET_SET_FLAGS (old_editable, GTK_CAN_FOCUS);
+
+  old_editable->selection_start_pos = 0;
+  old_editable->selection_end_pos = 0;
+  old_editable->has_selection = FALSE;
+  old_editable->editable = 1;
+  old_editable->visible = 1;
+  old_editable->clipboard_text = NULL;
+
+#ifdef USE_XIM
+  old_editable->ic = NULL;
+#endif
+
+  gtk_selection_add_targets (GTK_WIDGET (old_editable), GDK_SELECTION_PRIMARY,
+                            targets, G_N_ELEMENTS (targets));
+}
+
+static void
+gtk_old_editable_insert_text (GtkEditable *editable,
+                             const gchar *new_text,
+                             gint         new_text_length,
+                             gint        *position)
+{
+  gchar buf[64];
+  gchar *text;
+
+  gtk_widget_ref (GTK_WIDGET (editable));
+
+  if (new_text_length <= 63)
+    text = buf;
+  else
+    text = g_new (gchar, new_text_length + 1);
+
+  text[new_text_length] = '\0';
+  strncpy (text, new_text, new_text_length);
+
+  gtk_signal_emit (GTK_OBJECT (editable), editable_signals[INSERT_TEXT], text, new_text_length, position);
+  gtk_signal_emit (GTK_OBJECT (editable), editable_signals[CHANGED]);
+
+  if (new_text_length > 63)
+    g_free (text);
+
+  gtk_widget_unref (GTK_WIDGET (editable));
+}
+
+static void
+gtk_old_editable_delete_text (GtkEditable *editable,
+                             gint         start_pos,
+                             gint         end_pos)
+{
+  GtkOldEditable *old_editable = GTK_OLD_EDITABLE (editable);
+
+  gtk_widget_ref (GTK_WIDGET (old_editable));
+
+  gtk_signal_emit (GTK_OBJECT (old_editable), editable_signals[DELETE_TEXT], start_pos, end_pos);
+  gtk_signal_emit (GTK_OBJECT (old_editable), editable_signals[CHANGED]);
+
+  if (old_editable->selection_start_pos == old_editable->selection_end_pos &&
+      old_editable->has_selection)
+    gtk_old_editable_claim_selection (old_editable, FALSE, GDK_CURRENT_TIME);
+  
+  gtk_widget_unref (GTK_WIDGET (old_editable));
+}
+
+static void
+gtk_old_editable_update_text (GtkOldEditable *old_editable,
+                             gint            start_pos,
+                             gint            end_pos)
+{
+  GtkOldEditableClass *klass = GTK_OLD_EDITABLE_GET_CLASS (old_editable);
+  klass->update_text (GTK_OLD_EDITABLE (old_editable), start_pos, end_pos);
+}
+
+static gchar *    
+gtk_old_editable_get_chars  (GtkEditable      *editable,
+                            gint              start,
+                            gint              end)
+{
+  GtkOldEditableClass *klass = GTK_OLD_EDITABLE_GET_CLASS (editable);
+  return klass->get_chars (GTK_OLD_EDITABLE (editable), start, end);
+}
+
+/*
+ * Like gtk_editable_get_chars, but if the editable is not
+ * visible, return asterisks; also convert result to UTF-8.
+ */
+static void *    
+gtk_old_editable_get_public_chars (GtkOldEditable   *old_editable,
+                                  gint              start,
+                                  gint              end)
+{
+  gchar *str = NULL;
+  gchar *charset;
+  gboolean need_conversion = !g_get_charset (&charset);
+
+  if (old_editable->visible)
+    {
+      GError *error;
+      gchar *tmp = gtk_editable_get_chars (GTK_EDITABLE (old_editable), start, end);
+
+      if (need_conversion)
+       {
+         str = g_convert (tmp, -1,
+                          "UTF-8", charset,
+                          NULL, NULL, &error);
+         
+         if (!str)
+           {
+             g_warning ("Cannot convert text from charset to UTF-8 %s: %s", charset, error->message);
+             g_error_free (error);
+           }
+
+         g_free (tmp);
+       }
+      else
+       str = tmp;
+    }
+  else
+    {
+      gint i;
+      gint nchars = end - start;
+       
+      if (nchars < 0)
+       nchars = -nchars;
+
+      str = g_new (gchar, nchars + 1);
+      for (i = 0; i<nchars; i++)
+       str[i] = '*';
+      str[i] = '\0';
+    }
+
+  return str;
+}
+
+static void
+gtk_old_editable_set_selection (GtkOldEditable *old_editable,
+                               gint            start_pos,
+                               gint            end_pos)
+{
+  GtkOldEditableClass *klass = GTK_OLD_EDITABLE_GET_CLASS (old_editable);
+  klass->set_selection (old_editable, start_pos, end_pos);
+}
+
+static void
+gtk_old_editable_set_position (GtkEditable *editable,
+                              gint            position)
+{
+  GtkOldEditableClass *klass = GTK_OLD_EDITABLE_GET_CLASS (editable);
+
+  klass->set_position (GTK_OLD_EDITABLE (editable), position);
+}
+
+static gint
+gtk_old_editable_get_position (GtkEditable *editable)
+{
+  return GTK_OLD_EDITABLE (editable)->current_pos;
+}
+
+static gint
+gtk_old_editable_selection_clear (GtkWidget         *widget,
+                                 GdkEventSelection *event)
+{
+  GtkOldEditable *old_editable = GTK_OLD_EDITABLE (widget);
+  
+  /* Let the selection handling code know that the selection
+   * has been changed, since we've overriden the default handler */
+  if (!gtk_selection_clear (widget, event))
+    return FALSE;
+  
+  if (old_editable->has_selection)
+    {
+      old_editable->has_selection = FALSE;
+      gtk_old_editable_update_text (old_editable, old_editable->selection_start_pos,
+                                   old_editable->selection_end_pos);
+    }
+  
+  return TRUE;
+}
+
+static void
+gtk_old_editable_selection_get (GtkWidget        *widget,
+                               GtkSelectionData *selection_data,
+                               guint             info,
+                               guint             time)
+{
+  GtkOldEditable *old_editable = GTK_OLD_EDITABLE (widget);
+  gint selection_start_pos;
+  gint selection_end_pos;
+
+  gchar *str;
+
+  selection_start_pos = MIN (old_editable->selection_start_pos, old_editable->selection_end_pos);
+  selection_end_pos = MAX (old_editable->selection_start_pos, old_editable->selection_end_pos);
+
+  str = gtk_old_editable_get_public_chars (old_editable, 
+                                          selection_start_pos, 
+                                          selection_end_pos);
+
+  if (str)
+    {
+      gtk_selection_data_set_text (selection_data, str);
+      g_free (str);
+    }
+}
+
+static void
+gtk_old_editable_paste_received (GtkOldEditable *old_editable,
+                                const gchar    *text,
+                                gboolean        is_clipboard)
+{
+  const gchar *str = NULL;
+  gchar *charset;
+  gboolean need_conversion = FALSE;
+
+  if (text)
+    {
+      GError *error;
+      
+      need_conversion = !g_get_charset (&charset);
+
+      if (need_conversion)
+       {
+         str = g_convert_with_fallback (text, -1,
+                                        charset, "UTF-8", NULL,
+                                        NULL, NULL, &error);
+         if (!str)
+           {
+             g_warning ("Cannot convert text from UTF-8 to %s: %s",
+                        charset, error->message);
+             g_error_free (error);
+             return;
+           }
+       }
+      else
+       str = text;
+    }
+
+  if (str)
+    {
+      gboolean reselect;
+      gint old_pos;
+      gint tmp_pos;
+  
+      reselect = FALSE;
+
+      if ((old_editable->selection_start_pos != old_editable->selection_end_pos) && 
+         (!old_editable->has_selection || is_clipboard))
+       {
+         reselect = TRUE;
+         
+         /* Don't want to call gtk_editable_delete_selection here if we are going
+          * to reclaim the selection to avoid extra server traffic */
+         if (old_editable->has_selection)
+           {
+             gtk_editable_delete_text (GTK_EDITABLE (old_editable),
+                                       MIN (old_editable->selection_start_pos, old_editable->selection_end_pos),
+                                       MAX (old_editable->selection_start_pos, old_editable->selection_end_pos));
+           }
+         else
+           gtk_editable_delete_selection (GTK_EDITABLE (old_editable));
+       }
+      
+      tmp_pos = old_pos = old_editable->current_pos;
+      
+      gtk_editable_insert_text (GTK_EDITABLE (old_editable), str, -1, &tmp_pos);
+
+      if (reselect)
+       gtk_old_editable_set_selection (old_editable, old_pos, old_editable->current_pos);
+
+      if (str && str != text)
+       g_free ((gchar *) str);
+    }
+}
+
+static void
+gtk_old_editable_selection_received  (GtkWidget         *widget,
+                                     GtkSelectionData  *selection_data,
+                                     guint              time)
+{
+  GtkOldEditable *old_editable = GTK_OLD_EDITABLE (widget);
+
+  gchar *text = gtk_selection_data_get_text (selection_data);
+
+  if (!text)
+    {
+      /* If we asked for UTF8 and didn't get it, try text; if we asked
+       * for text and didn't get it, try string.  If we asked for
+       * anything else and didn't get it, give up.
+       */
+      if (selection_data->target == gdk_atom_intern ("UTF8_STRING", FALSE))
+       {
+         gtk_selection_convert (widget, GDK_SELECTION_PRIMARY,
+                                gdk_atom_intern ("TEXT", FALSE),
+                                time);
+         return;
+       }
+      else if (selection_data->target == gdk_atom_intern ("TEXT", FALSE))
+       {
+         gtk_selection_convert (widget, GDK_SELECTION_PRIMARY,
+                                GDK_TARGET_STRING,
+                                time);
+         return;
+       }
+    }
+
+  if (text)
+    {
+      gtk_old_editable_paste_received (old_editable, text, FALSE);
+      g_free (text);
+    }
+}
+
+static void
+old_editable_text_received_cb (GtkClipboard *clipboard,
+                              const gchar  *text,
+                              gpointer      data)
+{
+  GtkOldEditable *old_editable = GTK_OLD_EDITABLE (data);
+
+  gtk_old_editable_paste_received (old_editable, text, TRUE);
+  g_object_unref (G_OBJECT (old_editable));
+}
+
+void
+gtk_old_editable_claim_selection (GtkOldEditable *old_editable, 
+                                 gboolean        claim, 
+                                 guint32         time)
+{
+  g_return_if_fail (old_editable != NULL);
+  g_return_if_fail (GTK_IS_OLD_EDITABLE (old_editable));
+  g_return_if_fail (GTK_WIDGET_REALIZED (old_editable));
+
+  old_editable->has_selection = FALSE;
+  
+  if (claim)
+    {
+      if (gtk_selection_owner_set (GTK_WIDGET (old_editable), GDK_SELECTION_PRIMARY, time))
+       old_editable->has_selection = TRUE;
+    }
+  else
+    {
+      if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == GTK_WIDGET (old_editable)->window)
+       gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, time);
+    }
+}
+
+static void
+gtk_old_editable_set_selection_bounds (GtkEditable *editable,
+                                      gint         start,
+                                      gint         end)
+{
+  GtkOldEditable *old_editable = GTK_OLD_EDITABLE (editable);
+  
+  if (GTK_WIDGET_REALIZED (editable))
+    gtk_old_editable_claim_selection (old_editable, start != end, GDK_CURRENT_TIME);
+  
+  gtk_old_editable_set_selection (old_editable, start, end);
+}
+
+static gboolean
+gtk_old_editable_get_selection_bounds (GtkEditable *editable,
+                                      gint        *start,
+                                      gint        *end)
+{
+  GtkOldEditable *old_editable = GTK_OLD_EDITABLE (editable);
+
+  *start = old_editable->selection_start_pos;
+  *end = old_editable->selection_end_pos;
+
+  return (old_editable->selection_start_pos != old_editable->selection_end_pos);
+}
+
+static void
+gtk_old_editable_real_set_editable (GtkOldEditable *old_editable,
+                                   gboolean        is_editable)
+{
+  is_editable = is_editable != FALSE;
+
+  if (old_editable->editable != is_editable)
+    {
+      old_editable->editable = is_editable;
+      gtk_widget_queue_draw (GTK_WIDGET (old_editable));
+    }
+}
+
+static void
+gtk_old_editable_real_cut_clipboard (GtkOldEditable *old_editable)
+{
+  gtk_old_editable_real_copy_clipboard (old_editable);
+  gtk_editable_delete_selection (GTK_EDITABLE (old_editable));
+}
+
+static void
+gtk_old_editable_real_copy_clipboard (GtkOldEditable *old_editable)
+{
+  gint selection_start_pos; 
+  gint selection_end_pos;
+
+  selection_start_pos = MIN (old_editable->selection_start_pos, old_editable->selection_end_pos);
+  selection_end_pos = MAX (old_editable->selection_start_pos, old_editable->selection_end_pos);
+
+  if (selection_start_pos != selection_end_pos)
+    {
+      gchar *text = gtk_old_editable_get_public_chars (old_editable,
+                                                      selection_start_pos,
+                                                      selection_end_pos);
+
+      if (text)
+       {
+         gtk_clipboard_set_text (gtk_clipboard_get (GDK_NONE), text, -1);
+         g_free (text);
+       }
+    }
+}
+
+static void
+gtk_old_editable_real_paste_clipboard (GtkOldEditable *old_editable)
+{
+  g_object_ref (G_OBJECT (old_editable));
+  gtk_clipboard_request_text (gtk_clipboard_get (GDK_NONE),
+                             old_editable_text_received_cb, old_editable);
+}
+
+void
+gtk_old_editable_changed (GtkOldEditable *old_editable)
+{
+  g_return_if_fail (old_editable != NULL);
+  g_return_if_fail (GTK_IS_OLD_EDITABLE (old_editable));
+  
+  gtk_signal_emit (GTK_OBJECT (old_editable), editable_signals[CHANGED]);
+}
diff --git a/gtk/gtkoldeditable.h b/gtk/gtkoldeditable.h
new file mode 100644 (file)
index 0000000..5736539
--- /dev/null
@@ -0,0 +1,142 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#ifndef __GTK_OLD_EDITABLE_H__
+#define __GTK_OLD_EDITABLE_H__
+
+
+#include <gdk/gdk.h>
+#include <gtk/gtkeditable.h>
+#include <gtk/gtkwidget.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+#define GTK_TYPE_OLD_EDITABLE            (gtk_old_editable_get_type ())
+#define GTK_OLD_EDITABLE(obj)            (GTK_CHECK_CAST ((obj), GTK_TYPE_OLD_EDITABLE, GtkOldEditable))
+#define GTK_OLD_EDITABLE_CLASS(klass)    (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_OLD_EDITABLE, GtkOldEditableClass))
+#define GTK_IS_OLD_EDITABLE(obj)         (GTK_CHECK_TYPE ((obj), GTK_TYPE_OLD_EDITABLE))
+#define GTK_IS_OLD_EDITABLE_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_OLD_EDITABLE))
+#define GTK_OLD_EDITABLE_GET_CLASS(obj)  (GTK_CHECK_GET_CLASS ((obj), GTK_TYPE_OLD_EDITABLE, GtkOldEditableClass))
+
+
+typedef struct _GtkOldEditable       GtkOldEditable;
+typedef struct _GtkOldEditableClass  GtkOldEditableClass;
+
+typedef void (*GtkTextFunction) (GtkOldEditable  *editable, guint32 time);
+
+struct _GtkOldEditable
+{
+  GtkWidget widget;
+
+  /*< public >*/
+  guint      current_pos;
+
+  guint      selection_start_pos;
+  guint      selection_end_pos;
+  guint      has_selection : 1;
+
+  /*< private >*/
+  guint      editable : 1;
+  guint      visible : 1;
+  GdkIC     *ic;
+  GdkICAttr *ic_attr;
+  
+  gchar *clipboard_text;
+};
+
+struct _GtkOldEditableClass
+{
+  GtkWidgetClass parent_class;
+  
+  /* Signals for notification/filtering of changes */
+  void (* changed)      (GtkOldEditable    *editable);
+  void (* insert_text)  (GtkOldEditable    *editable,
+                        const gchar       *text,
+                        gint               length,
+                        gint              *position);
+  void (* delete_text)  (GtkOldEditable    *editable,
+                        gint               start_pos,
+                        gint               end_pos);
+
+  /* Bindings actions */
+  void (* activate)        (GtkOldEditable *editable);
+  void (* set_editable)    (GtkOldEditable *editable,
+                           gboolean        is_editable);
+  void (* move_cursor)     (GtkOldEditable *editable,
+                           gint            x,
+                           gint            y);
+  void (* move_word)       (GtkOldEditable *editable,
+                           gint            n);
+  void (* move_page)       (GtkOldEditable *editable,
+                           gint            x,
+                           gint            y);
+  void (* move_to_row)     (GtkOldEditable *editable,
+                           gint            row);
+  void (* move_to_column)  (GtkOldEditable *editable,
+                           gint            row);
+  void (* kill_char)       (GtkOldEditable *editable,
+                           gint            direction);
+  void (* kill_word)       (GtkOldEditable *editable,
+                           gint            direction);
+  void (* kill_line)       (GtkOldEditable *editable,
+                           gint            direction);
+  void (* cut_clipboard)   (GtkOldEditable *editable);
+  void (* copy_clipboard)  (GtkOldEditable *editable);
+  void (* paste_clipboard) (GtkOldEditable *editable);
+
+  /* Virtual functions. get_chars is in paricular not a signal because
+   * it returns malloced memory. The others are not signals because
+   * they would not be particularly useful as such. (All changes to
+   * selection and position do not go through these functions)
+   */
+  void (* update_text)  (GtkOldEditable  *editable,
+                        gint             start_pos,
+                        gint             end_pos);
+  gchar* (* get_chars)  (GtkOldEditable  *editable,
+                        gint             start_pos,
+                        gint             end_pos);
+  void (* set_selection)(GtkOldEditable  *editable,
+                        gint             start_pos,
+                        gint             end_pos);
+  void (* set_position) (GtkOldEditable  *editable,
+                        gint             position);
+};
+
+GtkType    gtk_old_editable_get_type        (void) G_GNUC_CONST;
+void       gtk_old_editable_claim_selection (GtkOldEditable *old_editable,
+                                            gboolean        claim,
+                                            guint32         time);
+void       gtk_old_editable_changed         (GtkOldEditable *old_editable);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GTK_OLD_EDITABLE_H__ */
index 420bd0aa54bee0b22a146749b4f25cdb799e88f2..5e4da66dfd19a94d719375100080562a862c664f 100644 (file)
@@ -184,7 +184,6 @@ gtk_preview_init (GtkPreview *preview)
 void
 gtk_preview_uninit (void)
 {
-
   /* unimplemented */
 }
 
index 70dfcdf084fcf848f7cad469dd932788b4927dfd..06587a2dc9af9be5d187ef5c0f6a9a8d3fa31fe8 100644 (file)
@@ -26,9 +26,6 @@
 
 #include "config.h"
 
-#include "glib.h"
-#include "gdkconfig.h"
-
 #ifdef GDK_WINDOWING_X11
 #include <X11/Xlocale.h>       /* so we get the right setlocale */
 #else
@@ -56,6 +53,9 @@
 #include <io.h>
 #endif
 
+#include <glib.h>
+#include "gdkconfig.h"
+
 #include "gtkrc.h"
 #include "gtkbindings.h"
 #include "gtkthemes.h"
@@ -127,6 +127,8 @@ static guint       gtk_rc_parse_pixmap_path          (GScanner        *scanner);
 static void        gtk_rc_parse_pixmap_path_string   (gchar           *pix_path);
 static guint       gtk_rc_parse_module_path          (GScanner        *scanner);
 static void        gtk_rc_parse_module_path_string   (gchar           *mod_path);
+static guint       gtk_rc_parse_im_module_path       (GScanner        *scanner);
+static guint       gtk_rc_parse_im_module_file       (GScanner        *scanner);
 static guint       gtk_rc_parse_path_pattern         (GScanner        *scanner);
 static guint       gtk_rc_parse_stock                (GScanner        *scanner,
                                                       GtkRcStyle      *rc_style,
@@ -225,12 +227,17 @@ static const struct
   { "engine", GTK_RC_TOKEN_ENGINE },
   { "module_path", GTK_RC_TOKEN_MODULE_PATH },
   { "stock", GTK_RC_TOKEN_STOCK },
+  { "im_module_path", GTK_RC_TOKEN_IM_MODULE_PATH },
+  { "im_module_file", GTK_RC_TOKEN_IM_MODULE_FILE },
   { "LTR", GTK_RC_TOKEN_LTR },
   { "RTL", GTK_RC_TOKEN_RTL }
 };
 
 static const guint n_symbols = sizeof (symbols) / sizeof (symbols[0]);
 
+static gchar *im_module_path = NULL;
+static gchar *im_module_file = NULL;
+
 static GHashTable *rc_style_ht = NULL;
 static GHashTable *realized_style_ht = NULL;
 static GSList *gtk_rc_sets_widget = NULL;
@@ -304,42 +311,80 @@ get_themes_directory (void)
 
 #endif
  
-gchar *
-gtk_rc_get_theme_dir(void)
+static gchar *
+gtk_rc_make_default_dir (const gchar *type)
 {
   gchar *var, *path;
 
 #ifndef G_OS_WIN32
-  var = getenv("GTK_DATA_PREFIX");
+  var = getenv("GTK_EXE_PREFIX");
   if (var)
-    path = g_strdup_printf("%s%s", var, "/share/themes");
+    path = g_strdup_printf("%s%s%s", var, "/lib/gtk-2.0/" GTK_VERSION "/", type);
   else
-    path = g_strdup_printf("%s%s", GTK_DATA_PREFIX, "/share/themes");
+    path = g_strdup_printf("%s%s%s", GTK_EXE_PREFIX, "/lib/gtk-2.0/" GTK_VERSION "/", type);
 #else
-  path = g_strdup (get_themes_directory ());
+  path = g_strdup_printf ("%s\\%s", get_themes_directory (), type);
 #endif
 
   return path;
 }
 
 gchar *
-gtk_rc_get_module_dir(void)
+gtk_rc_get_im_module_path (void)
+{
+  gchar *result = g_getenv ("GTK_IM_MODULE_PATH");
+
+  if (!result)
+    {
+      if (im_module_path)
+       result = im_module_path;
+      else
+       return gtk_rc_make_default_dir ("immodules");
+    }
+
+  return g_strdup (result);
+}
+
+gchar *
+gtk_rc_get_im_module_file (void)
+{
+  gchar *result = g_getenv ("GTK_IM_MODULE_FILE");
+
+  if (!result)
+    {
+      if (im_module_file)
+       result = im_module_file;
+      else
+       result = GTK_SYSCONFDIR G_DIR_SEPARATOR_S "gtk-2.0" G_DIR_SEPARATOR_S "gtk.immodules";
+    }
+
+  return g_strdup (result);
+}
+
+gchar *
+gtk_rc_get_theme_dir(void)
 {
   gchar *var, *path;
 
 #ifndef G_OS_WIN32
-  var = getenv("GTK_EXE_PREFIX");
+  var = getenv("GTK_DATA_PREFIX");
   if (var)
-    path = g_strdup_printf("%s%s", var, "/lib/gtk-2.0/" GTK_VERSION "/engines");
+    path = g_strdup_printf("%s%s", var, "/share/themes");
   else
-    path = g_strdup_printf("%s%s", GTK_EXE_PREFIX, "/lib/gtk-2.0/" GTK_VERSION "/engines");
+    path = g_strdup_printf("%s%s", GTK_DATA_PREFIX, "/share/themes");
 #else
-  path = g_strdup_printf ("%s%s", get_themes_directory (), "\\engines");
+  path = g_strdup (get_themes_directory ());
 #endif
 
   return path;
 }
 
+gchar *
+gtk_rc_get_module_dir(void)
+{
+  return gtk_rc_make_default_dir ("engines");
+}
+
 static void
 gtk_rc_append_default_module_path(void)
 {
@@ -1544,6 +1589,12 @@ gtk_rc_parse_statement (GScanner *scanner)
     case GTK_RC_TOKEN_MODULE_PATH:
       return gtk_rc_parse_module_path (scanner);
        
+    case GTK_RC_TOKEN_IM_MODULE_PATH:
+      return gtk_rc_parse_im_module_path (scanner);
+       
+    case GTK_RC_TOKEN_IM_MODULE_FILE:
+      return gtk_rc_parse_im_module_file (scanner);
+       
     default:
       g_scanner_get_next_token (scanner);
       return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_STYLE;
@@ -2120,7 +2171,7 @@ gtk_rc_parse_engine (GScanner      *scanner,
       GtkRcStyleClass *new_class;
       
       new_style = gtk_theme_engine_create_rc_style (engine);
-      gtk_theme_engine_unref (engine);
+      g_type_module_unuse (G_TYPE_MODULE (engine));
 
       new_class = GTK_RC_STYLE_GET_CLASS (new_style);
 
@@ -2460,6 +2511,48 @@ gtk_rc_parse_module_path (GScanner *scanner)
   return G_TOKEN_NONE;
 }
 
+static guint
+gtk_rc_parse_im_module_path (GScanner *scanner)
+{
+  guint token;
+  
+  token = g_scanner_get_next_token (scanner);
+  if (token != GTK_RC_TOKEN_IM_MODULE_FILE)
+    return GTK_RC_TOKEN_IM_MODULE_FILE;
+  
+  token = g_scanner_get_next_token (scanner);
+  if (token != G_TOKEN_STRING)
+    return G_TOKEN_STRING;
+
+  if (im_module_path)
+    g_free (im_module_path);
+    
+  im_module_path = g_strdup (scanner->value.v_string);
+
+  return G_TOKEN_NONE;
+}
+
+static guint
+gtk_rc_parse_im_module_file (GScanner *scanner)
+{
+  guint token;
+  
+  token = g_scanner_get_next_token (scanner);
+  if (token != GTK_RC_TOKEN_IM_MODULE_FILE)
+    return GTK_RC_TOKEN_IM_MODULE_FILE;
+  
+  token = g_scanner_get_next_token (scanner);
+  if (token != G_TOKEN_STRING)
+    return G_TOKEN_STRING;
+
+  if (im_module_file)
+    g_free (im_module_file);
+    
+  im_module_file = g_strdup (scanner->value.v_string);
+
+  return G_TOKEN_NONE;
+}
+
 static void
 gtk_rc_parse_module_path_string (gchar *mod_path)
 {
index 0b37039311f8129bf5b099c94969f076d74de0a9..5f281fc6ccb8f62a26ddc2880b355b9a740a23ed 100644 (file)
@@ -148,6 +148,8 @@ gchar*              gtk_rc_find_pixmap_in_path      (GScanner       *scanner,
 gchar*         gtk_rc_find_module_in_path      (const gchar    *module_file);
 gchar*         gtk_rc_get_theme_dir            (void);
 gchar*         gtk_rc_get_module_dir           (void);
+gchar*         gtk_rc_get_im_module_path       (void);
+gchar*         gtk_rc_get_im_module_file       (void);
 
 /* private functions/definitions */
 typedef enum {
@@ -182,6 +184,8 @@ typedef enum {
   GTK_RC_TOKEN_HIGHEST,
   GTK_RC_TOKEN_ENGINE,
   GTK_RC_TOKEN_MODULE_PATH,
+  GTK_RC_TOKEN_IM_MODULE_PATH,
+  GTK_RC_TOKEN_IM_MODULE_FILE,
   GTK_RC_TOKEN_STOCK,
   GTK_RC_TOKEN_LTR,
   GTK_RC_TOKEN_RTL,
index 4193ba28afe0b9428111c4f2d98c27fbf4fb0d9f..b5a55a8a9a1ae96caff49da4969a1eab723d502c 100644 (file)
@@ -113,10 +113,10 @@ static gint gtk_spin_button_key_release    (GtkWidget          *widget,
                                            GdkEventKey        *event);
 static gint gtk_spin_button_scroll         (GtkWidget          *widget,
                                            GdkEventScroll     *event);
-static void gtk_spin_button_activate       (GtkEditable        *editable);
+static void gtk_spin_button_activate       (GtkEntry           *entry);
 static void gtk_spin_button_snap           (GtkSpinButton      *spin_button,
                                            gfloat              val);
-static void gtk_spin_button_insert_text    (GtkEditable        *editable,
+static void gtk_spin_button_insert_text    (GtkEntry           *entry,
                                            const gchar        *new_text,
                                            gint                new_text_length,
                                            gint               *position);
@@ -161,11 +161,11 @@ gtk_spin_button_class_init (GtkSpinButtonClass *class)
   GObjectClass     *gobject_class = G_OBJECT_CLASS (class);
   GtkObjectClass   *object_class;
   GtkWidgetClass   *widget_class;
-  GtkEditableClass *editable_class;
+  GtkEntryClass    *entry_class;
 
   object_class   = (GtkObjectClass*)   class;
   widget_class   = (GtkWidgetClass*)   class;
-  editable_class = (GtkEditableClass*) class; 
+  entry_class    = (GtkEntryClass*)    class; 
 
   parent_class = gtk_type_class (GTK_TYPE_ENTRY);
 
@@ -192,8 +192,8 @@ gtk_spin_button_class_init (GtkSpinButtonClass *class)
   widget_class->leave_notify_event = gtk_spin_button_leave_notify;
   widget_class->focus_out_event = gtk_spin_button_focus_out;
 
-  editable_class->insert_text = gtk_spin_button_insert_text;
-  editable_class->activate = gtk_spin_button_activate;
+  entry_class->insert_text = gtk_spin_button_insert_text;
+  entry_class->activate = gtk_spin_button_activate;
 
   class->input = NULL;
   class->output = NULL;
@@ -756,7 +756,7 @@ gtk_spin_button_focus_out (GtkWidget     *widget,
   g_return_val_if_fail (GTK_IS_SPIN_BUTTON (widget), FALSE);
   g_return_val_if_fail (event != NULL, FALSE);
 
-  if (GTK_EDITABLE (widget)->editable)
+  if (GTK_ENTRY (widget)->editable)
     gtk_spin_button_update (GTK_SPIN_BUTTON (widget));
 
   return GTK_WIDGET_CLASS (parent_class)->focus_out_event (widget, event);
@@ -813,7 +813,7 @@ gtk_spin_button_button_press (GtkWidget      *widget,
          gtk_grab_add (widget);
          spin->button = event->button;
          
-         if (GTK_EDITABLE (widget)->editable)
+         if (GTK_ENTRY (widget)->editable)
            gtk_spin_button_update (spin);
          
          if (event->y <= widget->requisition.height / 2)
@@ -1066,7 +1066,7 @@ gtk_spin_button_key_press (GtkWidget     *widget,
 
   key_repeat = (event->time == spin->ev_time);
 
-  if (GTK_EDITABLE (widget)->editable &&
+  if (GTK_ENTRY (widget)->editable &&
       (key == GDK_Up || key == GDK_Down || 
        key == GDK_Page_Up || key == GDK_Page_Down))
     gtk_spin_button_update (spin);
@@ -1204,30 +1204,21 @@ gtk_spin_button_snap (GtkSpinButton *spin_button,
 }
 
 static void
-gtk_spin_button_activate (GtkEditable *editable)
+gtk_spin_button_activate (GtkEntry *entry)
 {
-  g_return_if_fail (editable != NULL);
-  g_return_if_fail (GTK_IS_SPIN_BUTTON (editable));
-
-  if (editable->editable)
-    gtk_spin_button_update (GTK_SPIN_BUTTON (editable));
+  if (entry->editable)
+    gtk_spin_button_update (GTK_SPIN_BUTTON (entry));
 }
 
 static void
-gtk_spin_button_insert_text (GtkEditable *editable,
+gtk_spin_button_insert_text (GtkEntry    *entry,
                             const gchar *new_text,
                             gint         new_text_length,
                             gint        *position)
 {
-  GtkEntry *entry;
-  GtkSpinButton *spin;
+  GtkEditable *editable = GTK_EDITABLE (entry);
+  GtkSpinButton *spin = GTK_SPIN_BUTTON (editable);
  
-  g_return_if_fail (editable != NULL);
-  g_return_if_fail (GTK_IS_SPIN_BUTTON (editable));
-
-  entry = GTK_ENTRY (editable);
-  spin  = GTK_SPIN_BUTTON (editable);
-
   if (spin->numeric)
     {
       struct lconv *lc;
@@ -1296,8 +1287,8 @@ gtk_spin_button_insert_text (GtkEditable *editable,
        }
     }
 
-  GTK_EDITABLE_CLASS (parent_class)->insert_text (editable, new_text,
-                                                 new_text_length, position);
+  GTK_ENTRY_CLASS (parent_class)->insert_text (entry, new_text,
+                                              new_text_length, position);
 }
 
 static void
@@ -1565,7 +1556,7 @@ gtk_spin_button_set_snap_to_ticks (GtkSpinButton *spin_button,
   if (new_val != spin_button->snap_to_ticks)
     {
       spin_button->snap_to_ticks = new_val;
-      if (new_val && GTK_EDITABLE (spin_button)->editable)
+      if (new_val && GTK_ENTRY (spin_button)->editable)
        gtk_spin_button_update (spin_button);
     }
 }
index 5994b1949f440a838d92f1a3b08121c43be59d96..cd8bf8dde814f406d7cd7847741aae9c5fd5b916 100644 (file)
@@ -219,24 +219,24 @@ static void  gtk_text_adjustment     (GtkAdjustment  *adjustment,
 static void  gtk_text_disconnect     (GtkAdjustment  *adjustment,
                                      GtkText        *text);
 
-static void gtk_text_insert_text       (GtkEditable       *editable,
-                                       const gchar       *new_text,
-                                       gint               new_text_length,
-                                       gint               *position);
-static void gtk_text_delete_text       (GtkEditable        *editable,
-                                       gint               start_pos,
-                                       gint               end_pos);
-static void gtk_text_update_text       (GtkEditable       *editable,
-                                       gint               start_pos,
-                                       gint               end_pos);
-static gchar *gtk_text_get_chars       (GtkEditable       *editable,
-                                       gint               start,
-                                       gint               end);
-static void gtk_text_set_selection     (GtkEditable       *editable,
-                                       gint               start,
-                                       gint               end);
-static void gtk_text_real_set_editable (GtkEditable       *editable,
-                                       gboolean           is_editable);
+static void   gtk_text_insert_text       (GtkOldEditable *old_editable,
+                                         const gchar    *new_text,
+                                         gint            new_text_length,
+                                         gint           *position);
+static void   gtk_text_delete_text       (GtkOldEditable *old_editable,
+                                         gint            start_pos,
+                                         gint            end_pos);
+static void   gtk_text_update_text       (GtkOldEditable *old_editable,
+                                         gint            start_pos,
+                                         gint            end_pos);
+static gchar *gtk_text_get_chars         (GtkOldEditable *old_editable,
+                                         gint            start,
+                                         gint            end);
+static void   gtk_text_set_selection     (GtkOldEditable *old_editable,
+                                         gint            start,
+                                         gint            end);
+static void   gtk_text_real_set_editable (GtkOldEditable *old_editable,
+                                         gboolean        is_editable);
 
 /* Event handlers */
 static void  gtk_text_draw              (GtkWidget         *widget,
@@ -346,24 +346,24 @@ static void move_cursor_ver (GtkText *text, int count);
 static void move_cursor_hor (GtkText *text, int count);
 
 /* Binding actions */
-static void gtk_text_move_cursor         (GtkEditable *editable,
-                                         gint         x,
-                                         gint         y);
-static void gtk_text_move_word           (GtkEditable *editable,
-                                         gint         n);
-static void gtk_text_move_page           (GtkEditable *editable,
-                                         gint         x,
-                                         gint         y);
-static void gtk_text_move_to_row         (GtkEditable *editable,
-                                         gint         row);
-static void gtk_text_move_to_column      (GtkEditable *editable,
-                                         gint         row);
-static void gtk_text_kill_char           (GtkEditable *editable,
-                                         gint         direction);
-static void gtk_text_kill_word           (GtkEditable *editable,
-                                         gint         direction);
-static void gtk_text_kill_line           (GtkEditable *editable,
-                                         gint         direction);
+static void gtk_text_move_cursor    (GtkOldEditable *old_editable,
+                                    gint            x,
+                                    gint            y);
+static void gtk_text_move_word      (GtkOldEditable *old_editable,
+                                    gint            n);
+static void gtk_text_move_page      (GtkOldEditable *old_editable,
+                                    gint            x,
+                                    gint            y);
+static void gtk_text_move_to_row    (GtkOldEditable *old_editable,
+                                    gint            row);
+static void gtk_text_move_to_column (GtkOldEditable *old_editable,
+                                    gint            row);
+static void gtk_text_kill_char      (GtkOldEditable *old_editable,
+                                    gint            direction);
+static void gtk_text_kill_word      (GtkOldEditable *old_editable,
+                                    gint            direction);
+static void gtk_text_kill_line      (GtkOldEditable *old_editable,
+                                    gint            direction);
 
 /* To be removed */
 static void gtk_text_move_forward_character    (GtkText          *text);
@@ -386,8 +386,8 @@ static void gtk_text_select_word               (GtkText          *text,
 static void gtk_text_select_line               (GtkText          *text,
                                                guint32           time);
 
-static void gtk_text_set_position  (GtkEditable       *editable,
-                                   gint               position);
+static void gtk_text_set_position (GtkOldEditable *old_editable,
+                                  gint            position);
 
 /* #define DEBUG_GTK_TEXT */
 
@@ -525,7 +525,7 @@ gtk_text_get_type (void)
         (GtkClassInitFunc) NULL,
       };
       
-      text_type = gtk_type_unique (GTK_TYPE_EDITABLE, &text_info);
+      text_type = gtk_type_unique (GTK_TYPE_OLD_EDITABLE, &text_info);
     }
   
   return text_type;
@@ -537,12 +537,12 @@ gtk_text_class_init (GtkTextClass *class)
   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
   GtkObjectClass *object_class;
   GtkWidgetClass *widget_class;
-  GtkEditableClass *editable_class;
+  GtkOldEditableClass *old_editable_class;
   
   object_class = (GtkObjectClass*) class;
   widget_class = (GtkWidgetClass*) class;
-  editable_class = (GtkEditableClass*) class;
-  parent_class = gtk_type_class (GTK_TYPE_EDITABLE);
+  old_editable_class = (GtkOldEditableClass*) class;
+  parent_class = gtk_type_class (GTK_TYPE_OLD_EDITABLE);
 
   gobject_class->finalize = gtk_text_finalize;
 
@@ -566,24 +566,24 @@ gtk_text_class_init (GtkTextClass *class)
   widget_class->focus_in_event = gtk_text_focus_in;
   widget_class->focus_out_event = gtk_text_focus_out;
 
-  editable_class->set_editable = gtk_text_real_set_editable;
-  editable_class->insert_text = gtk_text_insert_text;
-  editable_class->delete_text = gtk_text_delete_text;
+  old_editable_class->set_editable = gtk_text_real_set_editable;
+  old_editable_class->insert_text = gtk_text_insert_text;
+  old_editable_class->delete_text = gtk_text_delete_text;
   
-  editable_class->move_cursor = gtk_text_move_cursor;
-  editable_class->move_word = gtk_text_move_word;
-  editable_class->move_page = gtk_text_move_page;
-  editable_class->move_to_row = gtk_text_move_to_row;
-  editable_class->move_to_column = gtk_text_move_to_column;
+  old_editable_class->move_cursor = gtk_text_move_cursor;
+  old_editable_class->move_word = gtk_text_move_word;
+  old_editable_class->move_page = gtk_text_move_page;
+  old_editable_class->move_to_row = gtk_text_move_to_row;
+  old_editable_class->move_to_column = gtk_text_move_to_column;
   
-  editable_class->kill_char = gtk_text_kill_char;
-  editable_class->kill_word = gtk_text_kill_word;
-  editable_class->kill_line = gtk_text_kill_line;
+  old_editable_class->kill_char = gtk_text_kill_char;
+  old_editable_class->kill_word = gtk_text_kill_word;
+  old_editable_class->kill_line = gtk_text_kill_line;
   
-  editable_class->update_text = gtk_text_update_text;
-  editable_class->get_chars   = gtk_text_get_chars;
-  editable_class->set_selection = gtk_text_set_selection;
-  editable_class->set_position = gtk_text_set_position;
+  old_editable_class->update_text = gtk_text_update_text;
+  old_editable_class->get_chars   = gtk_text_get_chars;
+  old_editable_class->set_selection = gtk_text_set_selection;
+  old_editable_class->set_position = gtk_text_set_position;
 
   class->set_scroll_adjustments = gtk_text_set_adjustments;
 
@@ -721,7 +721,7 @@ gtk_text_init (GtkText *text)
   
   init_properties (text);
   
-  GTK_EDITABLE (text)->editable = FALSE;
+  GTK_OLD_EDITABLE (text)->editable = FALSE;
   
   gtk_text_set_adjustments (text, NULL, NULL);
   gtk_editable_set_position (GTK_EDITABLE (text), 0);
@@ -789,17 +789,17 @@ gtk_text_set_editable (GtkText *text,
 }
 
 static void
-gtk_text_real_set_editable (GtkEditable *editable,
-                           gboolean     is_editable)
+gtk_text_real_set_editable (GtkOldEditable *old_editable,
+                           gboolean        is_editable)
 {
   GtkText *text;
   
-  g_return_if_fail (editable != NULL);
-  g_return_if_fail (GTK_IS_TEXT (editable));
+  g_return_if_fail (old_editable != NULL);
+  g_return_if_fail (GTK_IS_TEXT (old_editable));
   
-  text = GTK_TEXT (editable);
+  text = GTK_TEXT (old_editable);
   
-  editable->editable = (is_editable != FALSE);
+  old_editable->editable = (is_editable != FALSE);
   
   if (is_editable)
     draw_cursor (text, TRUE);
@@ -932,7 +932,7 @@ gtk_text_insert (GtkText    *text,
                 const char *chars,
                 gint        nchars)
 {
-  GtkEditable *editable = GTK_EDITABLE (text);
+  GtkOldEditable *old_editable = GTK_OLD_EDITABLE (text);
   gboolean frozen = FALSE;
   
   gint new_line_count = 1;
@@ -1032,10 +1032,10 @@ gtk_text_insert (GtkText    *text,
    
       if (text->point.index < text->first_line_start_index)
        text->first_line_start_index += numwcs;
-      if (text->point.index < editable->selection_start_pos)
-       editable->selection_start_pos += numwcs;
-      if (text->point.index < editable->selection_end_pos)
-       editable->selection_end_pos += numwcs;
+      if (text->point.index < old_editable->selection_start_pos)
+       old_editable->selection_start_pos += numwcs;
+      if (text->point.index < old_editable->selection_end_pos)
+       old_editable->selection_end_pos += numwcs;
       /* We'll reset the cursor later anyways if we aren't frozen */
       if (text->point.index < text->cursor_mark.index)
        text->cursor_mark.index += numwcs;
@@ -1070,7 +1070,7 @@ gtk_text_forward_delete (GtkText *text,
                         guint    nchars)
 {
   guint old_lines, old_height;
-  GtkEditable *editable = GTK_EDITABLE (text);
+  GtkOldEditable *old_editable = GTK_OLD_EDITABLE (text);
   gboolean frozen = FALSE;
   
   g_return_val_if_fail (text != NULL, 0);
@@ -1111,12 +1111,12 @@ gtk_text_forward_delete (GtkText *text,
        text->first_line_start_index -= nchars;
     }
   
-  if (text->point.index < editable->selection_start_pos)
-    editable->selection_start_pos -= 
-      MIN(nchars, editable->selection_start_pos - text->point.index);
-  if (text->point.index < editable->selection_end_pos)
-    editable->selection_end_pos -= 
-      MIN(nchars, editable->selection_end_pos - text->point.index);
+  if (text->point.index < old_editable->selection_start_pos)
+    old_editable->selection_start_pos -= 
+      MIN(nchars, old_editable->selection_start_pos - text->point.index);
+  if (text->point.index < old_editable->selection_end_pos)
+    old_editable->selection_end_pos -= 
+      MIN(nchars, old_editable->selection_end_pos - text->point.index);
   /* We'll reset the cursor later anyways if we aren't frozen */
   if (text->point.index < text->cursor_mark.index)
     move_mark_n (&text->cursor_mark, 
@@ -1141,30 +1141,30 @@ gtk_text_forward_delete (GtkText *text,
 }
 
 static void
-gtk_text_set_position (GtkEditable *editable,
-                      gint position)
+gtk_text_set_position (GtkOldEditable *old_editable,
+                      gint            position)
 {
-  GtkText *text = (GtkText *) editable;
+  GtkText *text = (GtkText *) old_editable;
   
   undraw_cursor (text, FALSE);
   text->cursor_mark = find_mark (text, position);
   find_cursor (text, TRUE);
   draw_cursor (text, FALSE);
-  gtk_editable_select_region (editable, 0, 0);
+  gtk_editable_select_region (GTK_EDITABLE (old_editable), 0, 0);
 }
 
 static gchar *    
-gtk_text_get_chars (GtkEditable   *editable,
-                   gint           start_pos,
-                   gint           end_pos)
+gtk_text_get_chars (GtkOldEditable *old_editable,
+                   gint            start_pos,
+                   gint            end_pos)
 {
   GtkText *text;
 
   gchar *retval;
   
-  g_return_val_if_fail (editable != NULL, NULL);
-  g_return_val_if_fail (GTK_IS_TEXT (editable), NULL);
-  text = GTK_TEXT (editable);
+  g_return_val_if_fail (old_editable != NULL, NULL);
+  g_return_val_if_fail (GTK_IS_TEXT (old_editable), NULL);
+  text = GTK_TEXT (old_editable);
   
   if (end_pos < 0)
     end_pos = TEXT_LENGTH (text);
@@ -1277,7 +1277,7 @@ static void
 gtk_text_realize (GtkWidget *widget)
 {
   GtkText *text;
-  GtkEditable *editable;
+  GtkOldEditable *old_editable;
   GdkWindowAttr attributes;
   gint attributes_mask;
   
@@ -1285,7 +1285,7 @@ gtk_text_realize (GtkWidget *widget)
   g_return_if_fail (GTK_IS_TEXT (widget));
   
   text = GTK_TEXT (widget);
-  editable = GTK_EDITABLE (widget);
+  old_editable = GTK_OLD_EDITABLE (widget);
   GTK_WIDGET_SET_FLAGS (text, GTK_REALIZED);
   
   attributes.window_type = GDK_WINDOW_CHILD;
@@ -1341,12 +1341,12 @@ gtk_text_realize (GtkWidget *widget)
   gdk_gc_set_foreground (text->gc, &widget->style->text[GTK_STATE_NORMAL]);
   
 #ifdef USE_XIM
-  if (gdk_im_ready () && (editable->ic_attr = gdk_ic_attr_new ()) != NULL)
+  if (gdk_im_ready () && (old_editable->ic_attr = gdk_ic_attr_new ()) != NULL)
     {
       gint width, height;
       GdkColormap *colormap;
       GdkEventMask mask;
-      GdkICAttr *attr = editable->ic_attr;
+      GdkICAttr *attr = old_editable->ic_attr;
       GdkICAttributesType attrmask = GDK_IC_ALL_REQ;
       GdkIMStyle style;
       GdkIMStyle supported_style = GDK_IM_PREEDIT_NONE | 
@@ -1389,18 +1389,18 @@ gtk_text_realize (GtkWidget *widget)
          
          break;
        }
-      editable->ic = gdk_ic_new (attr, attrmask);
+      old_editable->ic = gdk_ic_new (attr, attrmask);
       
-      if (editable->ic == NULL)
+      if (old_editable->ic == NULL)
        g_warning ("Can't create input context.");
       else
        {
          mask = gdk_window_get_events (text->text_area);
-         mask |= gdk_ic_get_events (editable->ic);
+         mask |= gdk_ic_get_events (old_editable->ic);
          gdk_window_set_events (text->text_area, mask);
          
          if (GTK_WIDGET_HAS_FOCUS (widget))
-           gdk_im_begin (editable->ic, text->text_area);
+           gdk_im_begin (old_editable->ic, text->text_area);
        }
     }
 #endif
@@ -1409,8 +1409,8 @@ gtk_text_realize (GtkWidget *widget)
   gdk_window_show (text->text_area);
   init_properties (text);
 
-  if (editable->selection_start_pos != editable->selection_end_pos)
-    gtk_editable_claim_selection (editable, TRUE, GDK_CURRENT_TIME);
+  if (old_editable->selection_start_pos != old_editable->selection_end_pos)
+    gtk_old_editable_claim_selection (old_editable, TRUE, GDK_CURRENT_TIME);
   
   recompute_geometry (text);
 }
@@ -1467,15 +1467,15 @@ gtk_text_unrealize (GtkWidget *widget)
   text = GTK_TEXT (widget);
 
 #ifdef USE_XIM
-  if (GTK_EDITABLE (widget)->ic)
+  if (GTK_OLD_EDITABLE (widget)->ic)
     {
-      gdk_ic_destroy (GTK_EDITABLE (widget)->ic);
-      GTK_EDITABLE (widget)->ic = NULL;
+      gdk_ic_destroy (GTK_OLD_EDITABLE (widget)->ic);
+      GTK_OLD_EDITABLE (widget)->ic = NULL;
     }
-  if (GTK_EDITABLE (widget)->ic_attr)
+  if (GTK_OLD_EDITABLE (widget)->ic_attr)
     {
-      gdk_ic_attr_destroy (GTK_EDITABLE (widget)->ic_attr);
-      GTK_EDITABLE (widget)->ic_attr = NULL;
+      gdk_ic_attr_destroy (GTK_OLD_EDITABLE (widget)->ic_attr);
+      GTK_OLD_EDITABLE (widget)->ic_attr = NULL;
     }
 #endif
 
@@ -1628,14 +1628,14 @@ gtk_text_size_allocate (GtkWidget     *widget,
                        GtkAllocation *allocation)
 {
   GtkText *text;
-  GtkEditable *editable;
+  GtkOldEditable *old_editable;
   
   g_return_if_fail (widget != NULL);
   g_return_if_fail (GTK_IS_TEXT (widget));
   g_return_if_fail (allocation != NULL);
   
   text = GTK_TEXT (widget);
-  editable = GTK_EDITABLE (widget);
+  old_editable = GTK_OLD_EDITABLE (widget);
   
   widget->allocation = *allocation;
   if (GTK_WIDGET_REALIZED (widget))
@@ -1653,16 +1653,16 @@ gtk_text_size_allocate (GtkWidget     *widget,
                                                           (gint)TEXT_BORDER_ROOM) * 2));
       
 #ifdef USE_XIM
-      if (editable->ic && (gdk_ic_get_style (editable->ic) & GDK_IM_PREEDIT_POSITION))
+      if (old_editable->ic && (gdk_ic_get_style (old_editable->ic) & GDK_IM_PREEDIT_POSITION))
        {
          gint width, height;
          
          gdk_window_get_size (text->text_area, &width, &height);
-         editable->ic_attr->preedit_area.width = width;
-         editable->ic_attr->preedit_area.height = height;
+         old_editable->ic_attr->preedit_area.width = width;
+         old_editable->ic_attr->preedit_area.height = height;
 
-         gdk_ic_set_attr (editable->ic,
-                          editable->ic_attr, GDK_IC_PREEDIT_AREA);
+         gdk_ic_set_attr (old_editable->ic,
+                          old_editable->ic_attr, GDK_IC_PREEDIT_AREA);
        }
 #endif
       
@@ -1742,18 +1742,14 @@ gtk_text_button_press (GtkWidget      *widget,
                       GdkEventButton *event)
 {
   GtkText *text;
-  GtkEditable *editable;
-  static GdkAtom ctext_atom = GDK_NONE;
+  GtkOldEditable *old_editable;
   
   g_return_val_if_fail (widget != NULL, FALSE);
   g_return_val_if_fail (GTK_IS_TEXT (widget), FALSE);
   g_return_val_if_fail (event != NULL, FALSE);
   
-  if (ctext_atom == GDK_NONE)
-    ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE);
-  
   text = GTK_TEXT (widget);
-  editable = GTK_EDITABLE (widget);
+  old_editable = GTK_OLD_EDITABLE (widget);
   
   if (text->button && (event->button != text->button))
     return FALSE;
@@ -1776,8 +1772,8 @@ gtk_text_button_press (GtkWidget      *widget,
          
          /* Set it now, so we display things right. We'll unset it
           * later if things don't work out */
-         editable->has_selection = TRUE;
-         gtk_text_set_selection (GTK_EDITABLE(text),
+         old_editable->has_selection = TRUE;
+         gtk_text_set_selection (GTK_OLD_EDITABLE (text),
                                  text->cursor_mark.index,
                                  text->cursor_mark.index);
          
@@ -1797,10 +1793,10 @@ gtk_text_button_press (GtkWidget      *widget,
     }
   else if (event->type == GDK_BUTTON_PRESS)
     {
-      if ((event->button == 2) && editable->editable)
+      if ((event->button == 2) && old_editable->editable)
        {
-         if (editable->selection_start_pos == editable->selection_end_pos ||
-             editable->has_selection)
+         if (old_editable->selection_start_pos == old_editable->selection_end_pos ||
+             old_editable->has_selection)
            {
              undraw_cursor (text, FALSE);
              find_mouse_cursor (text, (gint)event->x, (gint)event->y);
@@ -1809,7 +1805,8 @@ gtk_text_button_press (GtkWidget      *widget,
            }
          
          gtk_selection_convert (widget, GDK_SELECTION_PRIMARY,
-                                ctext_atom, event->time);
+                                gdk_atom_intern ("UTF8_STRING", FALSE),
+                                event->time);
        }
       else
        {
@@ -1819,11 +1816,11 @@ gtk_text_button_press (GtkWidget      *widget,
          find_mouse_cursor (text, event->x, event->y);
          draw_cursor (text, FALSE);
          
-         gtk_text_set_selection (GTK_EDITABLE(text),
+         gtk_text_set_selection (GTK_OLD_EDITABLE (text),
                                  text->cursor_mark.index,
                                  text->cursor_mark.index);
          
-         editable->has_selection = FALSE;
+         old_editable->has_selection = FALSE;
          if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
            gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, event->time);
        }
@@ -1837,7 +1834,7 @@ gtk_text_button_release (GtkWidget      *widget,
                         GdkEventButton *event)
 {
   GtkText *text;
-  GtkEditable *editable;
+  GtkOldEditable *old_editable;
   g_return_val_if_fail (widget != NULL, FALSE);
   g_return_val_if_fail (GTK_IS_TEXT (widget), FALSE);
   g_return_val_if_fail (event != NULL, FALSE);
@@ -1860,20 +1857,20 @@ gtk_text_button_release (GtkWidget      *widget,
   if (event->button == 1)
     {
       text = GTK_TEXT (widget);
-      editable = GTK_EDITABLE (widget);
+      old_editable = GTK_OLD_EDITABLE (widget);
       
       gtk_grab_remove (widget);
       
-      editable->has_selection = FALSE;
-      if (editable->selection_start_pos != editable->selection_end_pos)
+      old_editable->has_selection = FALSE;
+      if (old_editable->selection_start_pos != old_editable->selection_end_pos)
        {
          if (gtk_selection_owner_set (widget,
                                       GDK_SELECTION_PRIMARY,
                                       event->time))
-           editable->has_selection = TRUE;
+           old_editable->has_selection = TRUE;
          else
-           gtk_text_update_text (editable, editable->selection_start_pos,
-                                 editable->selection_end_pos);
+           gtk_text_update_text (old_editable, old_editable->selection_start_pos,
+                                 old_editable->selection_end_pos);
        }
       else
        {
@@ -1943,20 +1940,20 @@ gtk_text_motion_notify (GtkWidget      *widget,
   find_mouse_cursor (GTK_TEXT (widget), x, y);
   draw_cursor (GTK_TEXT (widget), FALSE);
   
-  gtk_text_set_selection (GTK_EDITABLE(text), 
-                         GTK_EDITABLE(text)->selection_start_pos,
+  gtk_text_set_selection (GTK_OLD_EDITABLE (text), 
+                         GTK_OLD_EDITABLE (text)->selection_start_pos,
                          text->cursor_mark.index);
   
   return FALSE;
 }
 
 static void 
-gtk_text_insert_text    (GtkEditable       *editable,
+gtk_text_insert_text    (GtkOldEditable    *old_editable,
                         const gchar       *new_text,
                         gint               new_text_length,
                         gint              *position)
 {
-  GtkText *text = GTK_TEXT (editable);
+  GtkText *text = GTK_TEXT (old_editable);
   GdkFont *font;
   GdkColor *fore, *back;
 
@@ -1975,7 +1972,7 @@ gtk_text_insert_text    (GtkEditable       *editable,
 }
 
 static void 
-gtk_text_delete_text    (GtkEditable       *editable,
+gtk_text_delete_text    (GtkOldEditable    *old_editable,
                         gint               start_pos,
                         gint               end_pos)
 {
@@ -1983,7 +1980,7 @@ gtk_text_delete_text    (GtkEditable       *editable,
   
   g_return_if_fail (start_pos >= 0);
   
-  text = GTK_TEXT (editable);
+  text = GTK_TEXT (old_editable);
   
   gtk_text_set_point (text, start_pos);
   if (end_pos < 0)
@@ -1998,7 +1995,7 @@ gtk_text_key_press (GtkWidget   *widget,
                    GdkEventKey *event)
 {
   GtkText *text;
-  GtkEditable *editable;
+  GtkOldEditable *old_editable;
   gchar key;
   gint return_val;
   gint position;
@@ -2010,12 +2007,12 @@ gtk_text_key_press (GtkWidget   *widget,
   return_val = FALSE;
   
   text = GTK_TEXT (widget);
-  editable = GTK_EDITABLE (widget);
+  old_editable = GTK_OLD_EDITABLE (widget);
   
   key = event->keyval;
   return_val = TRUE;
   
-  if ((GTK_EDITABLE(text)->editable == FALSE))
+  if ((GTK_OLD_EDITABLE(text)->editable == FALSE))
     {
       switch (event->keyval)
        {
@@ -2050,7 +2047,7 @@ gtk_text_key_press (GtkWidget   *widget,
     {
       gint extend_selection;
       gint extend_start;
-      guint initial_pos = editable->current_pos;
+      guint initial_pos = old_editable->current_pos;
       
       text->point = find_mark (text, text->cursor_mark.index);
       
@@ -2059,15 +2056,15 @@ gtk_text_key_press (GtkWidget   *widget,
       
       if (extend_selection)
        {
-         editable->has_selection = TRUE;
+         old_editable->has_selection = TRUE;
          
-         if (editable->selection_start_pos == editable->selection_end_pos)
+         if (old_editable->selection_start_pos == old_editable->selection_end_pos)
            {
-             editable->selection_start_pos = text->point.index;
-             editable->selection_end_pos = text->point.index;
+             old_editable->selection_start_pos = text->point.index;
+             old_editable->selection_end_pos = text->point.index;
            }
          
-         extend_start = (text->point.index == editable->selection_start_pos);
+         extend_start = (text->point.index == old_editable->selection_start_pos);
        }
       
       switch (event->keyval)
@@ -2115,11 +2112,11 @@ gtk_text_key_press (GtkWidget   *widget,
          if (event->state & GDK_SHIFT_MASK)
            {
              extend_selection = FALSE;
-             gtk_editable_paste_clipboard (editable);
+             gtk_editable_paste_clipboard (GTK_EDITABLE (old_editable));
            }
          else if (event->state & GDK_CONTROL_MASK)
            {
-             gtk_editable_copy_clipboard (editable);
+             gtk_editable_copy_clipboard (GTK_EDITABLE (old_editable));
            }
          else
            {
@@ -2132,14 +2129,14 @@ gtk_text_key_press (GtkWidget   *widget,
          else if (event->state & GDK_SHIFT_MASK)
            {
              extend_selection = FALSE;
-             gtk_editable_cut_clipboard (editable);
+             gtk_editable_cut_clipboard (GTK_EDITABLE (old_editable));
            }
          else
            gtk_text_delete_forward_character (text);
          break;
        case GDK_Tab:
          position = text->point.index;
-         gtk_editable_insert_text (editable, "\t", 1, &position);
+         gtk_editable_insert_text (GTK_EDITABLE (old_editable), "\t", 1, &position);
          break;
        case GDK_Return:
          if (event->state & GDK_CONTROL_MASK)
@@ -2147,7 +2144,7 @@ gtk_text_key_press (GtkWidget   *widget,
          else
            {
              position = text->point.index;
-             gtk_editable_insert_text (editable, "\n", 1, &position);
+             gtk_editable_insert_text (GTK_EDITABLE (old_editable), "\n", 1, &position);
            }
          break;
        case GDK_Escape:
@@ -2165,7 +2162,7 @@ gtk_text_key_press (GtkWidget   *widget,
              
              if ((key >= 'a') && (key <= 'z') && control_keys[(int) (key - 'a')])
                {
-                 (* control_keys[(int) (key - 'a')]) (editable, event->time);
+                 (* control_keys[(int) (key - 'a')]) (old_editable, event->time);
                  return_val = TRUE;
                }
              
@@ -2178,7 +2175,7 @@ gtk_text_key_press (GtkWidget   *widget,
              
              if ((key >= 'a') && (key <= 'z') && alt_keys[(int) (key - 'a')])
                {
-                 (* alt_keys[(int) (key - 'a')]) (editable, event->time);
+                 (* alt_keys[(int) (key - 'a')]) (old_editable, event->time);
                  return_val = TRUE;
                }
              
@@ -2188,9 +2185,9 @@ gtk_text_key_press (GtkWidget   *widget,
            {
              extend_selection = FALSE;
              
-             gtk_editable_delete_selection (editable);
+             gtk_editable_delete_selection (GTK_EDITABLE (old_editable));
              position = text->point.index;
-             gtk_editable_insert_text (editable, event->string, event->length, &position);
+             gtk_editable_insert_text (GTK_EDITABLE (old_editable), event->string, event->length, &position);
              
              return_val = TRUE;
            }
@@ -2198,32 +2195,32 @@ gtk_text_key_press (GtkWidget   *widget,
            return_val = FALSE;
        }
       
-      if (return_val && (editable->current_pos != initial_pos))
+      if (return_val && (old_editable->current_pos != initial_pos))
        {
          if (extend_selection)
            {
-             if (editable->current_pos < editable->selection_start_pos)
-               gtk_text_set_selection (editable, editable->current_pos,
-                                       editable->selection_end_pos);
-             else if (editable->current_pos > editable->selection_end_pos)
-               gtk_text_set_selection (editable, editable->selection_start_pos,
-                                       editable->current_pos);
+             if (old_editable->current_pos < old_editable->selection_start_pos)
+               gtk_text_set_selection (old_editable, old_editable->current_pos,
+                                       old_editable->selection_end_pos);
+             else if (old_editable->current_pos > old_editable->selection_end_pos)
+               gtk_text_set_selection (old_editable, old_editable->selection_start_pos,
+                                       old_editable->current_pos);
              else
                {
                  if (extend_start)
-                   gtk_text_set_selection (editable, editable->current_pos,
-                                           editable->selection_end_pos);
+                   gtk_text_set_selection (old_editable, old_editable->current_pos,
+                                           old_editable->selection_end_pos);
                  else
-                   gtk_text_set_selection (editable, editable->selection_start_pos,
-                                           editable->current_pos);
+                   gtk_text_set_selection (old_editable, old_editable->selection_start_pos,
+                                           old_editable->current_pos);
                }
            }
          else
-           gtk_text_set_selection (editable, 0, 0);
+           gtk_text_set_selection (old_editable, 0, 0);
          
-         gtk_editable_claim_selection (editable,
-                                       editable->selection_start_pos != editable->selection_end_pos,
-                                       event->time);
+         gtk_old_editable_claim_selection (old_editable,
+                                           old_editable->selection_start_pos != old_editable->selection_end_pos,
+                                           event->time);
        }
     }
   
@@ -2244,8 +2241,8 @@ gtk_text_focus_in (GtkWidget     *widget,
   gtk_widget_draw_focus (widget);
   
 #ifdef USE_XIM
-  if (GTK_EDITABLE(widget)->ic)
-    gdk_im_begin (GTK_EDITABLE(widget)->ic, GTK_TEXT(widget)->text_area);
+  if (GTK_OLD_EDITABLE (widget)->ic)
+    gdk_im_begin (GTK_OLD_EDITABLE (widget)->ic, GTK_TEXT(widget)->text_area);
 #endif
   
   draw_cursor (GTK_TEXT(widget), TRUE);
@@ -3734,7 +3731,7 @@ static void
 find_cursor_at_line (GtkText* text, const LineParams* start_line, gint pixel_height)
 {
   GdkWChar ch;
-  GtkEditable *editable = (GtkEditable *)text;
+  GtkOldEditable *old_editable = (GtkOldEditable *)text;
   
   GtkPropertyMark mark        = start_line->start;
   TabStopMark  tab_mark    = start_line->tab_cont.tab_start;
@@ -3762,26 +3759,26 @@ find_cursor_at_line (GtkText* text, const LineParams* start_line, gint pixel_hei
     text->cursor_char = ch;
     
 #ifdef USE_XIM
-  if (GTK_WIDGET_HAS_FOCUS(text) && gdk_im_ready() && editable->ic && 
-      (gdk_ic_get_style (editable->ic) & GDK_IM_PREEDIT_POSITION))
+  if (GTK_WIDGET_HAS_FOCUS(text) && gdk_im_ready() && old_editable->ic && 
+      (gdk_ic_get_style (old_editable->ic) & GDK_IM_PREEDIT_POSITION))
     {
       GdkICAttributesType mask = GDK_IC_SPOT_LOCATION |
                                 GDK_IC_PREEDIT_FOREGROUND |
                                 GDK_IC_PREEDIT_BACKGROUND;
 
-      editable->ic_attr->spot_location.x = text->cursor_pos_x;
-      editable->ic_attr->spot_location.y
+      old_editable->ic_attr->spot_location.x = text->cursor_pos_x;
+      old_editable->ic_attr->spot_location.y
        = text->cursor_pos_y - text->cursor_char_offset;
-      editable->ic_attr->preedit_foreground = *MARK_CURRENT_FORE (text, &mark);
-      editable->ic_attr->preedit_background = *MARK_CURRENT_BACK (text, &mark);
+      old_editable->ic_attr->preedit_foreground = *MARK_CURRENT_FORE (text, &mark);
+      old_editable->ic_attr->preedit_background = *MARK_CURRENT_BACK (text, &mark);
 
       if (MARK_CURRENT_FONT (text, &mark)->type == GDK_FONT_FONTSET)
        {
          mask |= GDK_IC_PREEDIT_FONTSET;
-         editable->ic_attr->preedit_fontset = MARK_CURRENT_FONT (text, &mark);
+         old_editable->ic_attr->preedit_fontset = MARK_CURRENT_FONT (text, &mark);
        }
       
-      gdk_ic_set_attr (editable->ic, editable->ic_attr, mask);
+      gdk_ic_set_attr (old_editable->ic, old_editable->ic_attr, mask);
     }
 #endif 
 }
@@ -3799,7 +3796,7 @@ find_cursor (GtkText* text, gboolean scroll)
                             pixel_height_of(text, text->current_line));
     }
   
-  GTK_EDITABLE (text)->current_pos = text->cursor_mark.index;
+  GTK_OLD_EDITABLE (text)->current_pos = text->cursor_mark.index;
 }
 
 static void
@@ -4023,30 +4020,30 @@ move_cursor_hor (GtkText *text, int count)
 }
 
 static void 
-gtk_text_move_cursor (GtkEditable *editable,
-                     gint         x,
-                     gint         y)
+gtk_text_move_cursor (GtkOldEditable *old_editable,
+                     gint            x,
+                     gint            y)
 {
   if (x > 0)
     {
       while (x-- != 0)
-       move_cursor_hor (GTK_TEXT (editable), 1);
+       move_cursor_hor (GTK_TEXT (old_editable), 1);
     }
   else if (x < 0)
     {
       while (x++ != 0)
-       move_cursor_hor (GTK_TEXT (editable), -1);
+       move_cursor_hor (GTK_TEXT (old_editable), -1);
     }
   
   if (y > 0)
     {
       while (y-- != 0)
-       move_cursor_ver (GTK_TEXT (editable), 1);
+       move_cursor_ver (GTK_TEXT (old_editable), 1);
     }
   else if (y < 0)
     {
       while (y++ != 0)
-       move_cursor_ver (GTK_TEXT (editable), -1);
+       move_cursor_ver (GTK_TEXT (old_editable), -1);
     }
 }
 
@@ -4075,18 +4072,18 @@ gtk_text_move_previous_line (GtkText *text)
 }
 
 static void 
-gtk_text_move_word (GtkEditable *editable,
-                   gint         n)
+gtk_text_move_word (GtkOldEditable *old_editable,
+                   gint            n)
 {
   if (n > 0)
     {
       while (n-- != 0)
-       gtk_text_move_forward_word (GTK_TEXT (editable));
+       gtk_text_move_forward_word (GTK_TEXT (old_editable));
     }
   else if (n < 0)
     {
       while (n++ != 0)
-       gtk_text_move_backward_word (GTK_TEXT (editable));
+       gtk_text_move_backward_word (GTK_TEXT (old_editable));
     }
 }
 
@@ -4155,28 +4152,28 @@ gtk_text_move_backward_word (GtkText *text)
 }
 
 static void 
-gtk_text_move_page (GtkEditable *editable,
-                   gint         x,
-                   gint         y)
+gtk_text_move_page (GtkOldEditable *old_editable,
+                   gint            x,
+                   gint            y)
 {
   if (y != 0)
-    scroll_int (GTK_TEXT (editable), 
-               y * GTK_TEXT(editable)->vadj->page_increment);  
+    scroll_int (GTK_TEXT (old_editable), 
+               y * GTK_TEXT(old_editable)->vadj->page_increment);  
 }
 
 static void 
-gtk_text_move_to_row (GtkEditable *editable,
-                     gint         row)
+gtk_text_move_to_row (GtkOldEditable *old_editable,
+                     gint            row)
 {
 }
 
 static void 
-gtk_text_move_to_column (GtkEditable *editable,
-                        gint         column)
+gtk_text_move_to_column (GtkOldEditable *old_editable,
+                        gint            column)
 {
   GtkText *text;
   
-  text = GTK_TEXT (editable);
+  text = GTK_TEXT (old_editable);
   
   text->cursor_virtual_x = 0;  /* FIXME */
   
@@ -4205,37 +4202,37 @@ gtk_text_move_to_column (GtkEditable *editable,
 static void
 gtk_text_move_beginning_of_line (GtkText *text)
 {
-  gtk_text_move_to_column (GTK_EDITABLE (text), 0);
+  gtk_text_move_to_column (GTK_OLD_EDITABLE (text), 0);
   
 }
 
 static void
 gtk_text_move_end_of_line (GtkText *text)
 {
-  gtk_text_move_to_column (GTK_EDITABLE (text), -1);
+  gtk_text_move_to_column (GTK_OLD_EDITABLE (text), -1);
 }
 
 static void 
-gtk_text_kill_char (GtkEditable *editable,
-                   gint         direction)
+gtk_text_kill_char (GtkOldEditable *old_editable,
+                   gint            direction)
 {
   GtkText *text;
   
-  text = GTK_TEXT (editable);
+  text = GTK_TEXT (old_editable);
   
-  if (editable->selection_start_pos != editable->selection_end_pos)
-    gtk_editable_delete_selection (editable);
+  if (old_editable->selection_start_pos != old_editable->selection_end_pos)
+    gtk_editable_delete_selection (GTK_EDITABLE (old_editable));
   else
     {
       if (direction >= 0)
        {
          if (text->point.index + 1 <= TEXT_LENGTH (text))
-           gtk_editable_delete_text (editable, text->point.index, text->point.index + 1);
+           gtk_editable_delete_text (GTK_EDITABLE (old_editable), text->point.index, text->point.index + 1);
        }
       else
        {
          if (text->point.index > 0)
-           gtk_editable_delete_text (editable, text->point.index - 1, text->point.index);
+           gtk_editable_delete_text (GTK_EDITABLE (old_editable), text->point.index - 1, text->point.index);
        }
     }
 }
@@ -4243,33 +4240,33 @@ gtk_text_kill_char (GtkEditable *editable,
 static void
 gtk_text_delete_forward_character (GtkText *text)
 {
-  gtk_text_kill_char (GTK_EDITABLE (text), 1);
+  gtk_text_kill_char (GTK_OLD_EDITABLE (text), 1);
 }
 
 static void
 gtk_text_delete_backward_character (GtkText *text)
 {
-  gtk_text_kill_char (GTK_EDITABLE (text), -1);
+  gtk_text_kill_char (GTK_OLD_EDITABLE (text), -1);
 }
 
 static void 
-gtk_text_kill_word (GtkEditable *editable,
-                   gint         direction)
+gtk_text_kill_word (GtkOldEditable *old_editable,
+                   gint            direction)
 {
-  if (editable->selection_start_pos != editable->selection_end_pos)
-    gtk_editable_delete_selection (editable);
+  if (old_editable->selection_start_pos != old_editable->selection_end_pos)
+    gtk_editable_delete_selection (GTK_EDITABLE (old_editable));
   else
     {
-      gint old_pos = editable->current_pos;
+      gint old_pos = old_editable->current_pos;
       if (direction >= 0)
        {
-         gtk_text_move_word (editable, 1);
-         gtk_editable_delete_text (editable, old_pos, editable->current_pos);
+         gtk_text_move_word (old_editable, 1);
+         gtk_editable_delete_text (GTK_EDITABLE (old_editable), old_pos, old_editable->current_pos);
        }
       else
        {
-         gtk_text_move_word (editable, -1);
-         gtk_editable_delete_text (editable, editable->current_pos, old_pos);
+         gtk_text_move_word (old_editable, -1);
+         gtk_editable_delete_text (GTK_EDITABLE (old_editable), old_editable->current_pos, old_pos);
        }
     }
 }
@@ -4277,43 +4274,43 @@ gtk_text_kill_word (GtkEditable *editable,
 static void
 gtk_text_delete_forward_word (GtkText *text)
 {
-  gtk_text_kill_word (GTK_EDITABLE (text), 1);
+  gtk_text_kill_word (GTK_OLD_EDITABLE (text), 1);
 }
 
 static void
 gtk_text_delete_backward_word (GtkText *text)
 {
-  gtk_text_kill_word (GTK_EDITABLE (text), -1);
+  gtk_text_kill_word (GTK_OLD_EDITABLE (text), -1);
 }
 
 static void 
-gtk_text_kill_line (GtkEditable *editable,
-                   gint         direction)
+gtk_text_kill_line (GtkOldEditable *old_editable,
+                   gint            direction)
 {
-  gint old_pos = editable->current_pos;
+  gint old_pos = old_editable->current_pos;
   if (direction >= 0)
     {
-      gtk_text_move_to_column (editable, -1);
-      gtk_editable_delete_text (editable, old_pos, editable->current_pos);
+      gtk_text_move_to_column (old_editable, -1);
+      gtk_editable_delete_text (GTK_EDITABLE (old_editable), old_pos, old_editable->current_pos);
     }
   else
     {
-      gtk_text_move_to_column (editable, 0);
-      gtk_editable_delete_text (editable, editable->current_pos, old_pos);
+      gtk_text_move_to_column (old_editable, 0);
+      gtk_editable_delete_text (GTK_EDITABLE (old_editable), old_editable->current_pos, old_pos);
     }
 }
 
 static void
 gtk_text_delete_line (GtkText *text)
 {
-  gtk_text_move_to_column (GTK_EDITABLE (text), 0);
-  gtk_text_kill_line (GTK_EDITABLE (text), 1);
+  gtk_text_move_to_column (GTK_OLD_EDITABLE (text), 0);
+  gtk_text_kill_line (GTK_OLD_EDITABLE (text), 1);
 }
 
 static void
 gtk_text_delete_to_line_end (GtkText *text)
 {
-  gtk_text_kill_line (GTK_EDITABLE (text), 1);
+  gtk_text_kill_line (GTK_OLD_EDITABLE (text), 1);
 }
 
 static void
@@ -4322,8 +4319,8 @@ gtk_text_select_word (GtkText *text, guint32 time)
   gint start_pos;
   gint end_pos;
   
-  GtkEditable *editable;
-  editable = GTK_EDITABLE (text);
+  GtkOldEditable *old_editable;
+  old_editable = GTK_OLD_EDITABLE (text);
   
   gtk_text_move_backward_word (text);
   start_pos = text->cursor_mark.index;
@@ -4331,9 +4328,9 @@ gtk_text_select_word (GtkText *text, guint32 time)
   gtk_text_move_forward_word (text);
   end_pos = text->cursor_mark.index;
   
-  editable->has_selection = TRUE;
-  gtk_text_set_selection (editable, start_pos, end_pos);
-  gtk_editable_claim_selection (editable, start_pos != end_pos, time);
+  old_editable->has_selection = TRUE;
+  gtk_text_set_selection (old_editable, start_pos, end_pos);
+  gtk_old_editable_claim_selection (old_editable, start_pos != end_pos, time);
 }
 
 static void
@@ -4342,8 +4339,8 @@ gtk_text_select_line (GtkText *text, guint32 time)
   gint start_pos;
   gint end_pos;
   
-  GtkEditable *editable;
-  editable = GTK_EDITABLE (text);
+  GtkOldEditable *old_editable;
+  old_editable = GTK_OLD_EDITABLE (text);
   
   gtk_text_move_beginning_of_line (text);
   start_pos = text->cursor_mark.index;
@@ -4352,9 +4349,9 @@ gtk_text_select_line (GtkText *text, guint32 time)
   gtk_text_move_forward_character (text);
   end_pos = text->cursor_mark.index;
   
-  editable->has_selection = TRUE;
-  gtk_text_set_selection (editable, start_pos, end_pos);
-  gtk_editable_claim_selection (editable, start_pos != end_pos, time);
+  old_editable->has_selection = TRUE;
+  gtk_text_set_selection (old_editable, start_pos, end_pos);
+  gtk_old_editable_claim_selection (old_editable, start_pos != end_pos, time);
 }
 
 /**********************************************************************/
@@ -4867,19 +4864,18 @@ expand_scratch_buffer (GtkText* text, guint len)
 
 /* Side effect: modifies text->gc
  */
-
 static void
 draw_bg_rect (GtkText* text, GtkPropertyMark *mark,
              gint x, gint y, gint width, gint height,
              gboolean already_cleared)
 {
-  GtkEditable *editable = GTK_EDITABLE(text);
+  GtkOldEditable *old_editable = GTK_OLD_EDITABLE (text);
 
-  if ((mark->index >= MIN(editable->selection_start_pos, editable->selection_end_pos) &&
-       mark->index < MAX(editable->selection_start_pos, editable->selection_end_pos)))
+  if ((mark->index >= MIN(old_editable->selection_start_pos, old_editable->selection_end_pos) &&
+       mark->index < MAX(old_editable->selection_start_pos, old_editable->selection_end_pos)))
     {
       gtk_paint_flat_box(GTK_WIDGET(text)->style, text->text_area,
-                        editable->has_selection ?
+                        old_editable->has_selection ?
                            GTK_STATE_SELECTED : GTK_STATE_ACTIVE, 
                         GTK_SHADOW_NONE,
                         NULL, GTK_WIDGET(text), "text",
@@ -4921,10 +4917,10 @@ draw_line (GtkText* text,
   union { GdkWChar *wc; guchar *ch; } buffer;
   GdkGC *fg_gc;
   
-  GtkEditable *editable = GTK_EDITABLE(text);
+  GtkOldEditable *old_editable = GTK_OLD_EDITABLE (text);
   
-  guint selection_start_pos = MIN (editable->selection_start_pos, editable->selection_end_pos);
-  guint selection_end_pos = MAX (editable->selection_start_pos, editable->selection_end_pos);
+  guint selection_start_pos = MIN (old_editable->selection_start_pos, old_editable->selection_end_pos);
+  guint selection_end_pos = MAX (old_editable->selection_start_pos, old_editable->selection_end_pos);
   
   GtkPropertyMark mark = lp->start;
   TabStopMark tab_mark = lp->tab_cont.tab_start;
@@ -5044,7 +5040,7 @@ draw_line (GtkText* text,
          if ((mark.index >= selection_start_pos) && 
              (mark.index < selection_end_pos))
            {
-             if (editable->has_selection)
+             if (old_editable->has_selection)
                fg_gc = GTK_WIDGET(text)->style->fg_gc[GTK_STATE_SELECTED];
              else
                fg_gc = GTK_WIDGET(text)->style->fg_gc[GTK_STATE_ACTIVE];
@@ -5159,7 +5155,7 @@ draw_line_wrap (GtkText* text, guint height /* baseline height */)
 static void
 undraw_cursor (GtkText* text, gint absolute)
 {
-  GtkEditable *editable = (GtkEditable *)text;
+  GtkOldEditable *old_editable = (GtkOldEditable *) text;
 
   TDEBUG (("in undraw_cursor\n"));
   
@@ -5167,7 +5163,7 @@ undraw_cursor (GtkText* text, gint absolute)
     text->cursor_drawn_level = 0;
   
   if ((text->cursor_drawn_level ++ == 0) &&
-      (editable->selection_start_pos == editable->selection_end_pos) &&
+      (old_editable->selection_start_pos == old_editable->selection_end_pos) &&
       GTK_WIDGET_DRAWABLE (text) && text->line_start_cache)
     {
       GdkFont* font;
@@ -5225,7 +5221,7 @@ drawn_cursor_max (GtkText* text)
 static void
 draw_cursor (GtkText* text, gint absolute)
 {
-  GtkEditable *editable = (GtkEditable *)text;
+  GtkOldEditable *old_editable = (GtkOldEditable *)text;
   
   TDEBUG (("in draw_cursor\n"));
   
@@ -5233,8 +5229,8 @@ draw_cursor (GtkText* text, gint absolute)
     text->cursor_drawn_level = 1;
   
   if ((--text->cursor_drawn_level == 0) &&
-      editable->editable &&
-      (editable->selection_start_pos == editable->selection_end_pos) &&
+      old_editable->editable &&
+      (old_editable->selection_start_pos == old_editable->selection_end_pos) &&
       GTK_WIDGET_DRAWABLE (text) && text->line_start_cache)
     {
       GdkFont* font;
@@ -5339,11 +5335,11 @@ expose_text (GtkText* text, GdkRectangle *area, gboolean cursor)
 }
 
 static void 
-gtk_text_update_text    (GtkEditable       *editable,
-                        gint               start_pos,
-                        gint               end_pos)
+gtk_text_update_text (GtkOldEditable    *old_editable,
+                     gint               start_pos,
+                     gint               end_pos)
 {
-  GtkText *text = GTK_TEXT (editable);
+  GtkText *text = GTK_TEXT (old_editable);
   
   GList *cache = text->line_start_cache;
   gint pixels = - text->first_cut_pixels;
@@ -5454,11 +5450,11 @@ recompute_geometry (GtkText* text)
 /**********************************************************************/
 
 static void 
-gtk_text_set_selection  (GtkEditable   *editable,
-                        gint           start,
-                        gint           end)
+gtk_text_set_selection  (GtkOldEditable  *old_editable,
+                        gint             start,
+                        gint             end)
 {
-  GtkText *text = GTK_TEXT (editable);
+  GtkText *text = GTK_TEXT (old_editable);
   
   guint start1, end1, start2, end2;
   
@@ -5467,8 +5463,8 @@ gtk_text_set_selection  (GtkEditable   *editable,
   
   start1 = MIN(start,end);
   end1 = MAX(start,end);
-  start2 = MIN(editable->selection_start_pos, editable->selection_end_pos);
-  end2 = MAX(editable->selection_start_pos, editable->selection_end_pos);
+  start2 = MIN(old_editable->selection_start_pos, old_editable->selection_end_pos);
+  end2 = MAX(old_editable->selection_start_pos, old_editable->selection_end_pos);
   
   if (start2 < start1)
     {
@@ -5479,19 +5475,19 @@ gtk_text_set_selection  (GtkEditable   *editable,
     }
   
   undraw_cursor (text, FALSE);
-  editable->selection_start_pos = start;
-  editable->selection_end_pos = end;
+  old_editable->selection_start_pos = start;
+  old_editable->selection_end_pos = end;
   draw_cursor (text, FALSE);
   
   /* Expose only what changed */
   
   if (start1 < start2)
-    gtk_text_update_text (editable, start1, MIN(end1, start2));
+    gtk_text_update_text (old_editable, start1, MIN(end1, start2));
   
   if (end2 > end1)
-    gtk_text_update_text (editable, MAX(end1, start2), end2);
+    gtk_text_update_text (old_editable, MAX(end1, start2), end2);
   else if (end2 < end1)
-    gtk_text_update_text (editable, end2, end1);
+    gtk_text_update_text (old_editable, end2, end1);
 }
 
 
index 96eb30f183e05459b6985cca3b90d5a0a11b58cc..b51f7b56e86c6658049916012dde7333012c969e 100644 (file)
@@ -30,7 +30,7 @@
 
 #include <gdk/gdk.h>
 #include <gtk/gtkadjustment.h>
-#include <gtk/gtkeditable.h>
+#include <gtk/gtkoldeditable.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -64,7 +64,7 @@ struct _GtkPropertyMark
 
 struct _GtkText
 {
-  GtkEditable editable;
+  GtkOldEditable old_editable;
 
   GdkWindow *text_area;
 
@@ -169,7 +169,7 @@ struct _GtkText
 
 struct _GtkTextClass
 {
-  GtkEditableClass parent_class;
+  GtkOldEditableClass parent_class;
 
   void  (*set_scroll_adjustments)   (GtkText       *text,
                                     GtkAdjustment  *hadjustment,
index cbbd5cebea50dd38f07e9157d21ffad7c5bda9d4..7487d3d20cb87bd46cbc65db484245ef64a92a30 100644 (file)
@@ -92,11 +92,6 @@ static GtkTextLineData *gtk_text_layout_real_wrap (GtkTextLayout *layout,
                                                    /* may be NULL */
                                                    GtkTextLineData *line_data);
 
-static void gtk_text_layout_real_get_log_attrs (GtkTextLayout  *layout,
-                                                GtkTextLine    *line,
-                                                PangoLogAttr  **attrs,
-                                                gint           *n_attrs);
-
 static void gtk_text_layout_invalidated     (GtkTextLayout     *layout);
 
 static void gtk_text_layout_real_invalidate     (GtkTextLayout     *layout,
@@ -207,7 +202,6 @@ gtk_text_layout_class_init (GtkTextLayoutClass *klass)
   gobject_class->finalize = gtk_text_layout_finalize;
 
   klass->wrap = gtk_text_layout_real_wrap;
-  klass->get_log_attrs = gtk_text_layout_real_get_log_attrs;
   klass->invalidate = gtk_text_layout_real_invalidate;
   klass->free_line_data = gtk_text_layout_real_free_line_data;
 }
@@ -418,6 +412,69 @@ gtk_text_layout_get_cursor_visible (GtkTextLayout *layout)
   return layout->cursor_visible;
 }
 
+/**
+ * gtk_text_layout_set_preedit_string:
+ * @layout: a #PangoLayout
+ * @preedit_string: a string to display at the insertion point
+ * @preedit_attrs: a #PangoAttrList of attributes that apply to @preedit_string
+ * @cursor_pos: position of cursor within preedit string in chars
+ * 
+ * Set the preedit string and attributes. The preedit string is a
+ * string showing text that is currently being edited and not
+ * yet committed into the buffer.
+ **/
+void
+gtk_text_layout_set_preedit_string (GtkTextLayout *layout,
+                                   const gchar   *preedit_string,
+                                   PangoAttrList *preedit_attrs,
+                                   gint           cursor_pos)
+{
+  GtkTextIter iter;
+  GtkTextLine *line;
+  GtkTextLineData *line_data;
+
+  g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
+  g_return_if_fail (preedit_attrs != NULL || preedit_string == NULL);
+
+  if (layout->preedit_string)
+    g_free (layout->preedit_string);
+
+  if (layout->preedit_attrs)
+    pango_attr_list_unref (layout->preedit_attrs);
+
+  if (preedit_string)
+    {
+      layout->preedit_string = g_strdup (preedit_string);
+      layout->preedit_len = strlen (layout->preedit_string);
+      pango_attr_list_ref (preedit_attrs);
+      layout->preedit_attrs = preedit_attrs;
+
+      cursor_pos = CLAMP (cursor_pos, 0, g_utf8_strlen (layout->preedit_string, -1));
+      layout->preedit_cursor = g_utf8_offset_to_pointer (layout->preedit_string, cursor_pos) - layout->preedit_string;
+    }
+  else
+    {
+      layout->preedit_string = NULL;
+      layout->preedit_len = 0;
+      layout->preedit_attrs = NULL;
+      layout->preedit_cursor = 0;
+    }
+
+  /* Now invalidate the paragraph containing the cursor
+   */
+  gtk_text_buffer_get_iter_at_mark (layout->buffer, &iter,
+                                   gtk_text_buffer_get_mark (layout->buffer, "insert"));
+  
+  line = gtk_text_iter_get_text_line (&iter);
+  line_data = gtk_text_line_get_data (line, layout);
+  if (line_data)
+    {
+      gtk_text_layout_invalidate_cache (layout, line);
+      gtk_text_line_invalidate_wrap (line, line_data);
+      gtk_text_layout_invalidated (layout);
+    }
+}
+
 void
 gtk_text_layout_get_size (GtkTextLayout *layout,
                           gint *width,
@@ -483,16 +540,6 @@ gtk_text_layout_wrap (GtkTextLayout *layout,
   return (* GTK_TEXT_LAYOUT_GET_CLASS (layout)->wrap) (layout, line, line_data);
 }
 
-void
-gtk_text_layout_get_log_attrs (GtkTextLayout  *layout,
-                               GtkTextLine    *line,
-                               PangoLogAttr  **attrs,
-                               gint           *n_attrs)
-{
-  (* GTK_TEXT_LAYOUT_GET_CLASS (layout)->get_log_attrs)
-    (layout, line, attrs, n_attrs);
-}
-
 GSList*
 gtk_text_layout_get_lines (GtkTextLayout *layout,
                            /* [top_y, bottom_y) */
@@ -856,21 +903,6 @@ gtk_text_layout_real_wrap (GtkTextLayout   *layout,
   return line_data;
 }
 
-static void
-gtk_text_layout_real_get_log_attrs (GtkTextLayout  *layout,
-                                    GtkTextLine    *line,
-                                    PangoLogAttr  **attrs,
-                                    gint           *n_attrs)
-{
-  GtkTextLineDisplay *display;
-
-  g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
-
-  display = gtk_text_layout_get_line_display (layout, line, TRUE);
-  pango_layout_get_log_attrs (display->layout, attrs, n_attrs);
-  gtk_text_layout_free_line_display (layout, display);
-}
-
 /*
  * Layout utility functions
  */
@@ -1285,6 +1317,18 @@ add_child_attrs (GtkTextLayout      *layout,
 
       return;
     }
+
+  if (layout->preedit_string)
+    {
+      g_free (layout->preedit_string);
+      layout->preedit_string = NULL;
+    }
+
+  if (layout->preedit_attrs)
+    {
+      pango_attr_list_unref (layout->preedit_attrs);
+      layout->preedit_attrs = NULL;
+    }
   
   logical_rect.x = 0;
   logical_rect.y = -height * PANGO_SCALE;
@@ -1355,6 +1399,96 @@ allocate_child_widgets (GtkTextLayout      *layout,
 #endif
 }
 
+static void
+convert_color (GdkColor       *result,
+              PangoAttrColor *attr)
+{
+  result->red = attr->red;
+  result->blue = attr->blue;
+  result->green = attr->green;
+}
+
+/* This function is used to convert the preedit string attributes, which are
+ * standard PangoAttributes, into the custom attributes used by the text
+ * widget and insert them into a attr list with a given offset.
+ */
+static void
+add_preedit_attrs (GtkTextLayout     *layout,
+                  GtkTextAttributes *style,
+                  PangoAttrList     *attrs,
+                  gint               offset,
+                  gboolean           size_only)
+{
+  PangoAttrIterator *iter = pango_attr_list_get_iterator (layout->preedit_attrs);
+
+  do
+    {
+      GtkTextAppearance appearance = style->appearance;
+      PangoFontDescription font_desc;
+      PangoAttribute *insert_attr;
+      GSList *extra_attrs = NULL;
+      GSList *tmp_list;
+      gint start, end;
+
+      pango_attr_iterator_range (iter, &start, &end);
+
+      if (end == G_MAXINT)
+       end = layout->preedit_len;
+      
+      pango_attr_iterator_get_font (iter, style->font_desc,
+                                   &font_desc, size_only ? NULL : &extra_attrs);
+      
+      tmp_list = extra_attrs;
+      while (tmp_list)
+       {
+         PangoAttribute *attr = tmp_list->data;
+         
+         switch (attr->klass->type)
+           {
+           case PANGO_ATTR_FOREGROUND:
+             convert_color (&appearance.fg_color, (PangoAttrColor *)attr);
+             break;
+           case PANGO_ATTR_BACKGROUND:
+             convert_color (&appearance.bg_color, (PangoAttrColor *)attr);
+             appearance.draw_bg = TRUE;
+             break;
+           case PANGO_ATTR_UNDERLINE:
+             appearance.underline = ((PangoAttrInt *)attr)->value;
+             break;
+           case PANGO_ATTR_STRIKETHROUGH:
+             appearance.strikethrough = ((PangoAttrInt *)attr)->value;
+             break;
+           default:
+             break;
+           }
+         
+         pango_attribute_destroy (attr);
+         tmp_list = tmp_list->next;
+       }
+      
+      g_slist_free (extra_attrs);
+      
+      insert_attr = pango_attr_font_desc_new (&font_desc);
+      insert_attr->start_index = start + offset;
+      insert_attr->end_index = end + offset;
+      
+      pango_attr_list_insert (attrs, insert_attr);
+      
+      if (!size_only)
+       {
+         insert_attr = gtk_text_attr_appearance_new (&appearance);
+         
+         insert_attr->start_index = start + offset;
+         insert_attr->end_index = end + offset;
+         
+         pango_attr_list_insert (attrs, insert_attr); 
+       }
+    }
+  while (pango_attr_iterator_next (iter));
+
+  pango_attr_iterator_destroy (iter);
+}
+
 GtkTextLineDisplay *
 gtk_text_layout_get_line_display (GtkTextLayout *layout,
                                   GtkTextLine   *line,
@@ -1393,6 +1527,7 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout,
 
   display->size_only = size_only;
   display->line = line;
+  display->insert_index = -1;
 
   gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer),
                                    &iter, line, 0);
@@ -1454,8 +1589,9 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout,
                    */
 
                   gint byte_count = 0;
-
-                  while (TRUE)
+                 GtkTextLineSegment *prev_seg = NULL;
+  
+                 while (seg)
                     {
                       if (seg->type == &gtk_text_char_type)
                         {
@@ -1463,21 +1599,32 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout,
                           byte_offset += seg->byte_count;
                           byte_count += seg->byte_count;
                         }
-                      else if (seg->body.mark.visible)
+                     else if (seg->type == &gtk_text_right_mark_type ||
+                              seg->type == &gtk_text_left_mark_type)
                         {
-                          cursor_byte_offsets = g_slist_prepend (cursor_byte_offsets, GINT_TO_POINTER (byte_offset));
-                          cursor_segs = g_slist_prepend (cursor_segs, seg);
+                         /* If we have preedit string, break out of this loop - we'll almost
+                          * certainly have different attributes on the preedit string
+                          */
+
+                         if (layout->preedit_len > 0 &&
+                             gtk_text_btree_mark_is_insert (_gtk_text_buffer_get_btree (layout->buffer),
+                                                            seg->body.mark.obj))
+                           break;
+
+                         if (seg->body.mark.visible)
+                           {
+                             cursor_byte_offsets = g_slist_prepend (cursor_byte_offsets, GINT_TO_POINTER (byte_offset));
+                             cursor_segs = g_slist_prepend (cursor_segs, seg);
+                           }
                         }
+                     else
+                       break;
 
-                      if (!seg->next ||
-                          (seg->next->type != &gtk_text_right_mark_type &&
-                           seg->next->type != &gtk_text_left_mark_type &&
-                           seg->next->type != &gtk_text_char_type))
-                        break;
-
+                     prev_seg = seg;
                       seg = seg->next;
                     }
 
+                 seg = prev_seg; /* Back up one */
                   add_text_attrs (layout, style, byte_count, attrs,
                                   byte_offset - byte_count, size_only);
                 }
@@ -1519,12 +1666,38 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout,
       else if (seg->type == &gtk_text_right_mark_type ||
                seg->type == &gtk_text_left_mark_type)
         {
+         gint cursor_offset = 0;
+         
+         /* At the insertion point, add the preedit string, if any */
+         
+         if (gtk_text_btree_mark_is_insert (_gtk_text_buffer_get_btree (layout->buffer),
+                                            seg->body.mark.obj))
+           {
+             display->insert_index = byte_offset;
+             
+             if (layout->preedit_len > 0)
+               {
+                 byte_count += layout->preedit_len;
+                 text = g_realloc (text, byte_count);
+
+                 style = get_style (layout, &iter);
+                 add_preedit_attrs (layout, style, attrs, byte_offset, size_only);
+                 release_style (layout, style);
+         
+                 memcpy (text + byte_offset, layout->preedit_string, layout->preedit_len);
+                 byte_offset += layout->preedit_len;
+
+                 cursor_offset = layout->preedit_cursor - layout->preedit_len;
+               }
+           }
+         
+
           /* Display visible marks */
 
           if (seg->body.mark.visible)
             {
               cursor_byte_offsets = g_slist_prepend (cursor_byte_offsets,
-                                                     GINT_TO_POINTER (byte_offset));
+                                                     GINT_TO_POINTER (byte_offset + cursor_offset));
               cursor_segs = g_slist_prepend (cursor_segs, seg);
             }
         }
@@ -1602,6 +1775,46 @@ gtk_text_layout_free_line_display (GtkTextLayout      *layout,
     }
 }
 
+/* Functions to convert iter <=> index for the line of a GtkTextLineDisplay
+ * taking into account the preedit string, if necessary.
+ */
+gint
+line_display_iter_to_index (GtkTextLayout      *layout,
+                           GtkTextLineDisplay *display,
+                           const GtkTextIter  *iter)
+{
+  gint index;
+
+  g_return_val_if_fail (gtk_text_iter_get_text_line (iter) == display->line, 0);
+
+  index = gtk_text_iter_get_line_index (iter);
+
+  if (index >= display->insert_index)
+    index += layout->preedit_len;
+
+  return index;
+}
+
+void
+line_display_index_to_iter (GtkTextLayout      *layout,
+                           GtkTextLineDisplay *display,
+                           GtkTextIter        *iter,
+                           gint                index,
+                           gint                trailing)
+{
+  if (index >= display->insert_index + layout->preedit_len)
+    index -= layout->preedit_len;
+  else if (index > display->insert_index)
+    {
+      index = display->insert_index;
+      trailing = 0;
+    }
+  
+  gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer),
+                                   iter, display->line, index);
+  gtk_text_iter_forward_chars (iter, trailing);
+}
+
 /* FIXME: This really doesn't belong in this file ... */
 static GtkTextLineData*
 gtk_text_line_data_new (GtkTextLayout *layout,
@@ -1711,12 +1924,7 @@ gtk_text_layout_get_iter_at_pixel (GtkTextLayout *layout,
       trailing = 0;
     }
 
-  gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer),
-                                   target_iter,
-                                   line, byte_index);
-
-  while (trailing--)
-    gtk_text_iter_next_char (target_iter);
+  line_display_index_to_iter (layout, display, target_iter, byte_index, trailing);
 
   gtk_text_layout_free_line_display (layout, display);
 }
@@ -1746,6 +1954,7 @@ gtk_text_layout_get_cursor_locations (GtkTextLayout  *layout,
   GtkTextLine *line;
   GtkTextLineDisplay *display;
   gint line_top;
+  gint index;
 
   PangoRectangle pango_strong_pos;
   PangoRectangle pango_weak_pos;
@@ -1754,12 +1963,13 @@ gtk_text_layout_get_cursor_locations (GtkTextLayout  *layout,
   g_return_if_fail (iter != NULL);
 
   line = gtk_text_iter_get_text_line (iter);
+  display = gtk_text_layout_get_line_display (layout, line, FALSE);
+  index = line_display_iter_to_index (layout, display, iter);
+  
   line_top = gtk_text_btree_find_line_top (_gtk_text_buffer_get_btree (layout->buffer),
                                            line, layout);
-
-  display = gtk_text_layout_get_line_display (layout, line, FALSE);
-
-  pango_layout_get_cursor_pos (display->layout, gtk_text_iter_get_line_index (iter),
+  
+  pango_layout_get_cursor_pos (display->layout, index,
                                strong_pos ? &pango_strong_pos : NULL,
                                weak_pos ? &pango_weak_pos : NULL);
 
@@ -1885,7 +2095,7 @@ gtk_text_layout_get_iter_location (GtkTextLayout     *layout,
     }
   else
     {
-      byte_index = gtk_text_iter_get_line_index (iter);
+      byte_index = line_display_iter_to_index (layout, display, iter);
 
       pango_layout_index_to_pos (display->layout, byte_index, &pango_rect);
 
@@ -1898,6 +2108,8 @@ gtk_text_layout_get_iter_location (GtkTextLayout     *layout,
   gtk_text_layout_free_line_display (layout, display);
 }
 
+/* FFIXX */
+
 /* Find the iter for the logical beginning of the first display line whose
  * top y is >= y. If none exists, move the iter to the logical beginning
  * of the last line in the buffer.
@@ -2104,9 +2316,8 @@ gtk_text_layout_move_iter_to_previous_line (GtkTextLayout *layout,
   g_return_if_fail (iter != NULL);
 
   line = gtk_text_iter_get_text_line (iter);
-  line_byte = gtk_text_iter_get_line_index (iter);
-
   display = gtk_text_layout_get_line_display (layout, line, FALSE);
+  line_byte = line_display_iter_to_index (layout, display, iter);
 
   tmp_list = pango_layout_get_lines (display->layout);
   layout_line = tmp_list->data;
@@ -2122,7 +2333,7 @@ gtk_text_layout_move_iter_to_previous_line (GtkTextLayout *layout,
           gtk_text_layout_free_line_display (layout, display);
           display = gtk_text_layout_get_line_display (layout, prev_line, FALSE);
 
-          tmp_list =  pango_layout_get_lines (display->layout);
+         tmp_list = pango_layout_get_lines (display->layout);
 
           while (tmp_list->next)
             {
@@ -2132,12 +2343,10 @@ gtk_text_layout_move_iter_to_previous_line (GtkTextLayout *layout,
               byte_offset += layout_line->length;
             }
 
-          gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer),
-                                           iter, prev_line, byte_offset);
+         line_display_index_to_iter (layout, display, iter, byte_offset, 0);
         }
       else
-        gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer),
-                                         iter, line, 0);
+       line_display_index_to_iter (layout, display, iter, 0, 0);
     }
   else
     {
@@ -2151,8 +2360,7 @@ gtk_text_layout_move_iter_to_previous_line (GtkTextLayout *layout,
 
           if (line_byte < byte_offset + layout_line->length || !tmp_list->next)
             {
-              gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer),
-                                               iter, line, prev_offset);
+             line_display_index_to_iter (layout, display, iter, prev_offset, 0);
               break;
             }
 
@@ -2190,7 +2398,6 @@ gtk_text_layout_move_iter_to_next_line (GtkTextLayout *layout,
   g_return_if_fail (iter != NULL);
 
   line = gtk_text_iter_get_text_line (iter);
-  line_byte = gtk_text_iter_get_line_index (iter);
 
   while (line && !found_after)
     {
@@ -2198,6 +2405,7 @@ gtk_text_layout_move_iter_to_next_line (GtkTextLayout *layout,
       GSList *tmp_list;
 
       display = gtk_text_layout_get_line_display (layout, line, FALSE);
+      line_byte = line_display_iter_to_index (layout, display, iter);
 
       tmp_list = pango_layout_get_lines (display->layout);
       while (tmp_list && !found_after)
@@ -2206,9 +2414,7 @@ gtk_text_layout_move_iter_to_next_line (GtkTextLayout *layout,
 
           if (found)
             {
-              gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer),
-                                               iter, line,
-                                               byte_offset);
+             line_display_index_to_iter (layout, display, iter, byte_offset, 0);
               found_after = TRUE;
             }
           else if (line_byte < byte_offset + layout_line->length || !tmp_list->next)
@@ -2248,9 +2454,8 @@ gtk_text_layout_move_iter_to_line_end (GtkTextLayout *layout,
   g_return_if_fail (iter != NULL);
 
   line = gtk_text_iter_get_text_line (iter);
-  line_byte = gtk_text_iter_get_line_index (iter);
-
   display = gtk_text_layout_get_line_display (layout, line, FALSE);
+  line_byte = line_display_iter_to_index (layout, display, iter);
 
   tmp_list = pango_layout_get_lines (display->layout);
   while (tmp_list)
@@ -2259,11 +2464,13 @@ gtk_text_layout_move_iter_to_line_end (GtkTextLayout *layout,
 
       if (line_byte < byte_offset + layout_line->length || !tmp_list->next)
         {
-          gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer),
-                                           iter, line,
-                                           direction < 0 ? byte_offset : byte_offset + layout_line->length);
+         line_display_index_to_iter (layout, display, iter,
+                                     direction < 0 ? byte_offset : byte_offset + layout_line->length,
+                                     0);
 
-          /* FIXME: Move back one position to avoid going to next line
+          /* FIXME: As a bad hack, we move back one position to avoid going
+          * to next line on a forced break not at whitespace. Real fix
+          * is to keep track of whether marks are at leading or trailing edge?
            */
           if (direction < 0 && layout_line->length > 0)
             gtk_text_iter_prev_char (iter);
@@ -2304,9 +2511,9 @@ gtk_text_layout_move_iter_to_x (GtkTextLayout *layout,
   g_return_if_fail (iter != NULL);
 
   line = gtk_text_iter_get_text_line (iter);
-  line_byte = gtk_text_iter_get_line_index (iter);
 
   display = gtk_text_layout_get_line_display (layout, line, FALSE);
+  line_byte = line_display_iter_to_index (layout, display, iter);
 
   tmp_list = pango_layout_get_lines (display->layout);
   while (tmp_list)
@@ -2342,13 +2549,8 @@ gtk_text_layout_move_iter_to_x (GtkTextLayout *layout,
                                         x * PANGO_SCALE - x_offset,
                                         &byte_index, &trailing);
 
-          gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer),
-                                           iter,
-                                           line, byte_index);
-
-          while (trailing--)
-            gtk_text_iter_next_char (iter);
-
+         line_display_index_to_iter (layout, display, iter, byte_index, trailing);
+         
           break;
         }
 
@@ -2383,20 +2585,27 @@ gtk_text_layout_move_iter_visually (GtkTextLayout *layout,
                                     GtkTextIter   *iter,
                                     gint           count)
 {
+  GtkTextLineDisplay *display = NULL;
+
   g_return_if_fail (layout != NULL);
   g_return_if_fail (iter != NULL);
 
   while (count != 0)
     {
       GtkTextLine *line = gtk_text_iter_get_text_line (iter);
-      gint line_byte = gtk_text_iter_get_line_index (iter);
-      GtkTextLineDisplay *display = gtk_text_layout_get_line_display (layout, line, FALSE);
+      gint line_byte;
+      gint extra_back = 0;
 
       int byte_count = gtk_text_line_byte_count (line);
 
       int new_index;
       int new_trailing;
 
+      if (!display)
+       display = gtk_text_layout_get_line_display (layout, line, FALSE);
+      line_byte = line_display_iter_to_index (layout, display, iter);
+
       if (count > 0)
         {
           pango_layout_move_cursor_visually (display->layout, line_byte, 0, 1, &new_index, &new_trailing);
@@ -2408,16 +2617,32 @@ gtk_text_layout_move_iter_visually (GtkTextLayout *layout,
           count++;
         }
 
-      gtk_text_layout_free_line_display (layout, display);
-
-      if (new_index < 0)
+      /* We need to handle the preedit string specially. Well, we don't really need to
+       * handle it specially, since hopefully calling gtk_im_context_reset() will
+       * remove the preedit string; but if we start off in front of the preedit
+       * string (logically) and end up in or on the back edge of the preedit string,
+       * we should move the iter one place farther.
+       */
+      if (layout->preedit_len > 0 && display->insert_index >= 0)
+       {
+         if (line_byte == display->insert_index + layout->preedit_len &&
+             new_index < display->insert_index + layout->preedit_len)
+           {
+             line_byte = display->insert_index;
+             extra_back = 1;
+           }
+       }
+      
+      if (new_index < 0 || (new_index == 0 && extra_back))
         {
           line = gtk_text_line_previous (line);
+
           if (!line)
             return;
 
+         gtk_text_layout_free_line_display (layout, display);
+         display = gtk_text_layout_get_line_display (layout, line, FALSE);
           new_index = gtk_text_line_byte_count (line);
-
         }
       else if (new_index > byte_count)
         {
@@ -2425,16 +2650,17 @@ gtk_text_layout_move_iter_visually (GtkTextLayout *layout,
           if (!line)
             return;
 
+         gtk_text_layout_free_line_display (layout, display);
+         display = gtk_text_layout_get_line_display (layout, line, FALSE);
           new_index = 0;
         }
-
-      gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer),
-                                       iter,
-                                       line, new_index);
-      while (new_trailing--)
-        gtk_text_iter_next_char (iter);
+      
+       line_display_index_to_iter (layout, display, iter, new_index, new_trailing);
+       if (extra_back)
+        gtk_text_iter_prev_char (iter);
     }
 
+  gtk_text_layout_free_line_display (layout, display);
 }
 
 void
@@ -2472,5 +2698,3 @@ gtk_text_layout_spew (GtkTextLayout *layout)
           layout->height, layout->screen_width);
 #endif
 }
-
-
index 04ae9c0c772449c38e150d3441e796c698162696..dca8e362e55d65fb4fa88c765a4190f1817b0264 100644 (file)
@@ -156,6 +156,13 @@ struct _GtkTextLayout
   
   /* Whether to show the insertion cursor */
   guint cursor_visible : 1;
+
+  /* The preedit string and attributes, if any */
+
+  gchar *preedit_string;
+  PangoAttrList *preedit_attrs;
+  gint preedit_len;
+  gint preedit_cursor;
 };
 
 struct _GtkTextLayoutClass
@@ -221,6 +228,7 @@ struct _GtkTextLineDisplay
   gint right_margin;
   gint top_margin;
   gint bottom_margin;
+  gint insert_index;           /* Byte index of insert cursor within para or -1 */
 
   gboolean size_only;
   GtkTextLine *line;
@@ -238,8 +246,14 @@ void gtk_text_layout_set_contexts           (GtkTextLayout     *layout,
                                              PangoContext      *ltr_context,
                                              PangoContext      *rtl_context);
 void gtk_text_layout_default_style_changed  (GtkTextLayout     *layout);
 void gtk_text_layout_set_screen_width       (GtkTextLayout     *layout,
                                              gint               width);
+void gtk_text_layout_set_preedit_string     (GtkTextLayout     *layout,
+                                            const gchar       *preedit_string,
+                                            PangoAttrList     *preedit_attrs,
+                                            gint               cursor_pos);
+
 void     gtk_text_layout_set_cursor_visible (GtkTextLayout     *layout,
                                              gboolean           cursor_visible);
 gboolean gtk_text_layout_get_cursor_visible (GtkTextLayout     *layout);
@@ -302,10 +316,6 @@ void     gtk_text_layout_validate        (GtkTextLayout *layout,
 GtkTextLineData* gtk_text_layout_wrap  (GtkTextLayout   *layout,
                                         GtkTextLine     *line,
                                         GtkTextLineData *line_data); /* may be NULL */
-void     gtk_text_layout_get_log_attrs (GtkTextLayout  *layout,
-                                        GtkTextLine    *line,
-                                        PangoLogAttr  **attrs,
-                                        gint           *n_attrs);
 void     gtk_text_layout_changed              (GtkTextLayout     *layout,
                                                gint               y,
                                                gint               old_height,
index ef21c82fb38c2307ae2b09d4431c695304f619ab..707cc98cd4cfc28c223c7d63256929bbb3d43383 100644 (file)
 
 #include "gtkbindings.h"
 #include "gtkdnd.h"
+#include "gtkintl.h"
 #include "gtkmain.h"
+#include "gtkmenu.h"
+#include "gtkmenuitem.h"
 #include "gtksignal.h"
 #include "gtktext.h"
 #include "gtktextdisplay.h"
@@ -176,6 +179,7 @@ static void     gtk_text_view_set_attributes_from_style (GtkTextView        *tex
                                                          GtkStyle           *style);
 static void     gtk_text_view_ensure_layout         (GtkTextView        *text_view);
 static void     gtk_text_view_destroy_layout        (GtkTextView        *text_view);
+static void     gtk_text_view_reset_im_context      (GtkTextView        *text_view);
 static void     gtk_text_view_start_selection_drag  (GtkTextView        *text_view,
                                                      const GtkTextIter  *iter,
                                                      GdkEventButton     *event);
@@ -187,11 +191,13 @@ static void     gtk_text_view_start_selection_dnd   (GtkTextView        *text_vi
 static void     gtk_text_view_start_cursor_blink    (GtkTextView        *text_view);
 static void     gtk_text_view_stop_cursor_blink     (GtkTextView        *text_view);
 
-static void gtk_text_view_value_changed             (GtkAdjustment *adj,
-                                                     GtkTextView   *view);
-static void gtk_text_view_commit_handler            (GtkIMContext  *context,
-                                                     const gchar   *str,
-                                                     GtkTextView   *text_view);
+static void gtk_text_view_value_changed           (GtkAdjustment *adj,
+                                                  GtkTextView   *view);
+static void gtk_text_view_commit_handler          (GtkIMContext  *context,
+                                                  const gchar   *str,
+                                                  GtkTextView   *text_view);
+static void gtk_text_view_preedit_changed_handler (GtkIMContext  *context,
+                                                  GtkTextView   *text_view);
 
 static void gtk_text_view_mark_set_handler       (GtkTextBuffer     *buffer,
                                                   const GtkTextIter *location,
@@ -207,6 +213,9 @@ static void gtk_text_view_set_virtual_cursor_pos (GtkTextView       *text_view,
 static GtkAdjustment* get_hadjustment            (GtkTextView       *text_view);
 static GtkAdjustment* get_vadjustment            (GtkTextView       *text_view);
 
+static void gtk_text_view_popup_menu             (GtkTextView       *text_view,
+                                                 GdkEventButton    *event);
 /* Container methods */
 static void gtk_text_view_add    (GtkContainer *container,
                                   GtkWidget    *child);
@@ -682,6 +691,9 @@ gtk_text_view_init (GtkTextView *text_view)
   gtk_signal_connect (GTK_OBJECT (text_view->im_context), "commit",
                       GTK_SIGNAL_FUNC (gtk_text_view_commit_handler), text_view);
 
+  gtk_signal_connect (GTK_OBJECT (text_view->im_context), "preedit_changed",
+                     GTK_SIGNAL_FUNC (gtk_text_view_preedit_changed_handler), text_view);
+  
   text_view->editable = TRUE;
   text_view->cursor_visible = TRUE;
 
@@ -1578,7 +1590,6 @@ gtk_text_view_size_allocate (GtkWidget *widget,
   GdkRectangle right_rect;
   GdkRectangle top_rect;
   GdkRectangle bottom_rect;
-  GSList *tmp_list;
   
   text_view = GTK_TEXT_VIEW (widget);
 
@@ -1914,6 +1925,12 @@ gtk_text_view_unrealize (GtkWidget *widget)
       text_view->incremental_validate_idle = 0;
     }
   
+  if (text_view->popup_menu)
+    {
+      gtk_widget_destroy (text_view->popup_menu);
+      text_view->popup_menu = NULL;
+    }
+   
   text_window_unrealize (text_view->text_window);
 
   if (text_view->left_window)
@@ -2123,14 +2140,13 @@ gtk_text_view_key_press_event (GtkWidget *widget, GdkEventKey *event)
       get_buffer (text_view) == NULL)
     return FALSE;
 
-  if (GTK_WIDGET_CLASS (parent_class)->key_press_event &&
-      GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event))
-    return TRUE;
-
-  if (event->window != text_view->text_window->bin_window)
-    return FALSE;
-
   if (gtk_im_context_filter_keypress (text_view->im_context, event))
+    {
+      text_view->need_im_reset = TRUE;
+      return TRUE;
+    }
+  else if (GTK_WIDGET_CLASS (parent_class)->key_press_event &&
+          GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event))
     return TRUE;
   else if (event->keyval == GDK_Return)
     {
@@ -2179,14 +2195,18 @@ gtk_text_view_button_press_event (GtkWidget *widget, GdkEventButton *event)
       return FALSE;
     }
 
+#if 0
   /* debug hack */
   if (event->button == 3 && (event->state & GDK_CONTROL_MASK) != 0)
     _gtk_text_buffer_spew (GTK_TEXT_VIEW (widget)->buffer);
   else if (event->button == 3)
     gtk_text_layout_spew (GTK_TEXT_VIEW (widget)->layout);
+#endif
 
   if (event->type == GDK_BUTTON_PRESS)
     {
+      gtk_text_view_reset_im_context (text_view);
+   
       if (event->button == 1)
         {
           /* If we're in the selection, start a drag copy/move of the
@@ -2230,10 +2250,7 @@ gtk_text_view_button_press_event (GtkWidget *widget, GdkEventButton *event)
         }
       else if (event->button == 3)
         {
-          if (gtk_text_view_end_selection_drag (text_view, event))
-            return TRUE;
-          else
-            return FALSE;
+         gtk_text_view_popup_menu (text_view, event);
         }
     }
 
@@ -2287,6 +2304,7 @@ gtk_text_view_focus_in_event (GtkWidget *widget, GdkEventFocus *event)
       gtk_text_view_start_cursor_blink (text_view);
     }
 
+  text_view->need_im_reset = TRUE;
   gtk_im_context_focus_in (GTK_TEXT_VIEW (widget)->im_context);
 
   return FALSE;
@@ -2306,6 +2324,7 @@ gtk_text_view_focus_out_event (GtkWidget *widget, GdkEventFocus *event)
       gtk_text_view_stop_cursor_blink (text_view);
     }
 
+  text_view->need_im_reset = TRUE;
   gtk_im_context_focus_out (GTK_TEXT_VIEW (widget)->im_context);
 
   return FALSE;
@@ -2642,6 +2661,8 @@ gtk_text_view_move_cursor (GtkTextView     *text_view,
 
   gint cursor_x_pos = 0;
 
+  gtk_text_view_reset_im_context (text_view);
+   
   if (step == GTK_MOVEMENT_PAGES)
     {
       gtk_text_view_scroll_pages (text_view, count);
@@ -2847,6 +2868,8 @@ gtk_text_view_delete_from_cursor (GtkTextView   *text_view,
   GtkTextIter end;
   gboolean leave_one = FALSE;
 
+  gtk_text_view_reset_im_context (text_view);
+  
   if (type == GTK_DELETE_CHARS)
     {
       /* Char delete deletes the selection, if one exists */
@@ -3358,6 +3381,14 @@ gtk_text_view_destroy_layout (GtkTextView *text_view)
     }
 }
 
+static void
+gtk_text_view_reset_im_context (GtkTextView *text_view)
+{
+  if (text_view->need_im_reset)
+    text_view->need_im_reset = 0;
+
+  gtk_im_context_reset (text_view->im_context);
+}
 
 /*
  * DND feature
@@ -3836,6 +3867,21 @@ gtk_text_view_commit_handler (GtkIMContext  *context,
                                 0);
 }
 
+static void 
+gtk_text_view_preedit_changed_handler (GtkIMContext *context,
+                                      GtkTextView  *text_view)
+{
+  gchar *str;
+  PangoAttrList *attrs;
+  gint cursor_pos;
+
+  gtk_im_context_get_preedit_string (context, &str, &attrs, &cursor_pos);
+  gtk_text_layout_set_preedit_string (text_view->layout, str, attrs, cursor_pos);
+
+  pango_attr_list_unref (attrs);
+  g_free (str);
+}
+
 static void
 gtk_text_view_mark_set_handler (GtkTextBuffer     *buffer,
                                 const GtkTextIter *location,
@@ -3843,12 +3889,21 @@ gtk_text_view_mark_set_handler (GtkTextBuffer     *buffer,
                                 gpointer           data)
 {
   GtkTextView *text_view = GTK_TEXT_VIEW (data);
+  gboolean need_reset = FALSE;
 
   if (mark == gtk_text_buffer_get_insert (buffer))
     {
       text_view->virtual_cursor_x = -1;
       text_view->virtual_cursor_y = -1;
+      need_reset = TRUE;
+    }
+  else if (mark == gtk_text_buffer_get_selection_bound (buffer))
+    {
+      need_reset = TRUE;
     }
+
+  if (need_reset)
+    gtk_text_view_reset_im_context (text_view);
 }
 
 static void
@@ -3903,6 +3958,70 @@ gtk_text_view_set_virtual_cursor_pos (GtkTextView *text_view,
   text_view->virtual_cursor_y = (y == -1) ? strong_pos.y + strong_pos.height / 2 : y;
 }
 
+/* Quick hack of a popup menu
+ */
+static void
+activate_cb (GtkWidget   *menuitem,
+            GtkTextView *text_view)
+{
+  const gchar *signal = gtk_object_get_data (GTK_OBJECT (menuitem), "gtk-signal");
+  gtk_signal_emit_by_name (GTK_OBJECT (text_view), signal);
+}
+
+static void
+append_action_signal (GtkTextView  *text_view,
+                     GtkWidget    *menu,
+                     const gchar  *label,
+                     const gchar  *signal)
+{
+  GtkWidget *menuitem = gtk_menu_item_new_with_label (label);
+
+  gtk_object_set_data (GTK_OBJECT (menuitem), "gtk-signal", (char *)signal);
+  gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
+                     activate_cb, text_view);
+
+  gtk_widget_show (menuitem);
+  gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
+}
+       
+static void
+popup_menu_detach (GtkWidget *attach_widget,
+                  GtkMenu   *menu)
+{
+  GTK_TEXT_VIEW (attach_widget)->popup_menu = NULL;
+}
+
+static void
+gtk_text_view_popup_menu (GtkTextView    *text_view,
+                         GdkEventButton *event)
+{
+  if (!text_view->popup_menu)
+    {
+      GtkWidget *menuitem;
+      
+      text_view->popup_menu = gtk_menu_new ();
+
+      gtk_menu_attach_to_widget (GTK_MENU (text_view->popup_menu),
+                                GTK_WIDGET (text_view),
+                                popup_menu_detach);
+
+      append_action_signal (text_view, text_view->popup_menu, _("Cut"), "cut_clipboard");
+      append_action_signal (text_view, text_view->popup_menu, _("Copy"), "copy_clipboard");
+      append_action_signal (text_view, text_view->popup_menu, _("Paste"), "paste_clipboard");
+
+      menuitem = gtk_menu_item_new (); /* Separator */
+      gtk_widget_show (menuitem);
+      gtk_menu_shell_append (GTK_MENU_SHELL (text_view->popup_menu), menuitem);
+
+      gtk_im_multicontext_append_menuitems (GTK_IM_MULTICONTEXT (text_view->im_context),
+                                           GTK_MENU_SHELL (text_view->popup_menu));
+    }
+
+  gtk_menu_popup (GTK_MENU (text_view->popup_menu), NULL, NULL,
+                 NULL, NULL,
+                 event->button, event->time);
+}
+
 
 
 /* Child GdkWindows */
index 5d96ca7be83e147f3871f0f89e0bd070677244ff..5943aceab84f33c1a0d9446ab19ff28bdc4e3001 100644 (file)
@@ -70,13 +70,12 @@ struct _GtkTextView
   guint selection_drag_scan_timeout;
   gint scrolling_accel_factor;
 
-  gboolean overwrite_mode;
-
   GtkWrapMode wrap_mode;        /* Default wrap mode */
 
-  gboolean editable;            /* default editability */
-
-  gboolean cursor_visible;
+  guint editable : 1;           /* default editability */
+  guint overwrite_mode : 1;
+  guint cursor_visible : 1;
+  guint  need_im_reset : 1;    /* If we have reset the IM since the last character entered */
 
   GtkTextWindow *text_window;
   GtkTextWindow *left_window;
@@ -114,6 +113,7 @@ struct _GtkTextView
   guint incremental_validate_idle;      /* Idle to revalidate offscreen portions, runs after redraw */
 
   GtkIMContext *im_context;
+  GtkWidget *popup_menu;
 
   gint drag_start_x;
   gint drag_start_y;
index dc10495400cd64c5f8d5b125d7fba780494fead2..af3a2cb048c89107030f45b9f7c319ba979421da 100644 (file)
 #include <stdlib.h>
 #include <gmodule.h>
 #include "gtkthemes.h"
-#include "gtkmain.h"
 #include "gtkrc.h"
-#include "gtkselection.h"
-#include "gtksignal.h"
-#include "gtkwidget.h"
 #include "config.h"
 #include "gtkintl.h"
 
-/*****************************
- *****************************
- * temporary compat code, make GtkThemeEnginePlugin a GObject plus GTypePlugin interface
- */
-typedef struct _GtkThemeEnginePlugin GtkThemeEnginePlugin;
-typedef struct _GObjectClass         GtkThemeEnginePluginClass;
-static void gtk_theme_engine_plugin_use                (GTypePlugin     *plugin);
-static void gtk_theme_engine_plugin_unuse              (GTypePlugin     *plugin);
-static void gtk_theme_engine_plugin_complete_type_info (GTypePlugin     *plugin,
-                                                       GType            g_type,
-                                                       GTypeInfo       *info,
-                                                       GTypeValueTable *value_table);
-GType      gtk_theme_engine_plugin_get_type           (void);
-struct _GtkThemeEnginePlugin
-{
-  GObject parent_instance;
-
-  GtkThemeEngine *engine;
-  gchar *engine_name;
-  GTypeInfo info;
-  GType type;
-  GType parent_type;
-};
-#define GTK_TYPE_THEME_ENGINE_PLUGIN              (gtk_theme_engine_plugin_get_type ())
-#define GTK_THEME_ENGINE_PLUGIN(plugin)           (G_TYPE_CHECK_INSTANCE_CAST ((plugin), GTK_TYPE_THEME_ENGINE_PLUGIN, GtkThemeEnginePlugin))
-#define GTK_THEME_ENGINE_PLUGIN_CLASS(class)      (G_TYPE_CHECK_CLASS_CAST ((class), GTK_TYPE_THEME_ENGINE_PLUGIN, GtkThemeEnginePluginClass))
-#define GTK_IS_THEME_ENGINE_PLUGIN(plugin)        (G_TYPE_CHECK_INSTANCE_TYPE ((plugin), GTK_TYPE_THEME_ENGINE_PLUGIN))
-#define GTK_IS_THEME_ENGINE_PLUGIN_CLASS(class)   (G_TYPE_CHECK_CLASS_TYPE ((class), GTK_TYPE_THEME_ENGINE_PLUGIN))
-#define GTK_THEME_ENGINE_PLUGIN_GET_CLASS(plugin) (G_TYPE_INSTANCE_GET_CLASS ((plugin), GTK_TYPE_THEME_ENGINE_PLUGIN, GtkThemeEnginePluginClass))
-static void
-gtk_theme_engine_plugin_shutdown (GObject *object)
-{
-  GtkThemeEnginePlugin *plugin = GTK_THEME_ENGINE_PLUGIN (object);
-
-  g_warning (G_STRLOC ": shutdown should never happen for static type plugins");
-
-  g_object_ref (object);
-
-  /* chain parent class handler */
-  G_OBJECT_CLASS (g_type_class_peek_parent (GTK_THEME_ENGINE_PLUGIN_GET_CLASS (plugin)))->shutdown (object);
-}
-static void
-gtk_theme_engine_plugin_class_init (GtkThemeEnginePluginClass *class)
-{
-  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
-
-  gobject_class->shutdown = gtk_theme_engine_plugin_shutdown;
-}
-static void
-theme_engine_plugin_iface_init (GTypePluginClass *iface)
-{
-  iface->use_plugin = gtk_theme_engine_plugin_use;
-  iface->unuse_plugin = gtk_theme_engine_plugin_unuse;
-  iface->complete_type_info = gtk_theme_engine_plugin_complete_type_info;
-}
-GType
-gtk_theme_engine_plugin_get_type (void)
-{
-  static GType theme_engine_plugin_type = 0;
-
-  if (!theme_engine_plugin_type)
-    {
-      static const GTypeInfo theme_engine_plugin_info = {
-       sizeof (GtkThemeEnginePluginClass),
-       NULL,           /* base_init */
-       NULL,           /* base_finalize */
-       (GClassInitFunc) gtk_theme_engine_plugin_class_init,
-       NULL,           /* class_finalize */
-       NULL,           /* class_data */
-       sizeof (GtkThemeEnginePlugin),
-       0,              /* n_preallocs */
-       NULL,           /* instance_init */
-      };
-      static const GInterfaceInfo iface_info = {
-       (GInterfaceInitFunc) theme_engine_plugin_iface_init,
-       NULL,               /* interface_finalize */
-       NULL,               /* interface_data */
-      };
-
-      theme_engine_plugin_type = g_type_register_static (G_TYPE_OBJECT, "GtkThemeEnginePlugin", &theme_engine_plugin_info, 0);
-
-      g_type_add_interface_static (theme_engine_plugin_type, G_TYPE_TYPE_PLUGIN, &iface_info);
-    }
-
-  return theme_engine_plugin_type;
-}
-/* end of GtkThemeEnginePlugin object implementation stuff
- *****************************
- *****************************/
+typedef struct _GtkThemeEngineClass GtkThemeEngineClass;
 
 struct _GtkThemeEngine
 {
+  GTypeModule parent_instance;
+  
   GModule *library;
 
-  void (*init) (GtkThemeEngine *);
+  void (*init) (GTypeModule *);
   void (*exit) (void);
   GtkRcStyle *(*create_rc_style) ();
 
   gchar *name;
+};
 
-  GSList *plugins;             /* TypePlugins for this engine */
-  
-  guint refcount;
+struct _GtkThemeEngineClass
+{
+  GTypeModuleClass parent_class;
 };
 
 static GHashTable *engine_hash = NULL;
 
-#ifdef __EMX__
-static void gen_8_3_dll_name(gchar *name, gchar *fullname)
-{
-    /* 8.3 dll filename restriction */
-    fullname[0] = '_';
-    strncpy (fullname + 1, name, 7);
-    fullname[8] = '\0';
-    strcat (fullname, ".dll");
-}                                                      
-#endif
-
-GtkThemeEngine*
-gtk_theme_engine_get (const gchar *name)
+static gboolean
+gtk_theme_engine_load (GTypeModule *module)
 {
-  GtkThemeEngine *result;
+  GtkThemeEngine *engine = GTK_THEME_ENGINE (module);
   
-  if (!engine_hash)
-    engine_hash = g_hash_table_new (g_str_hash, g_str_equal);
-
-  /* get the library name for the theme */
+  gchar *fullname;
+  gchar *engine_path;
+      
+  fullname = g_module_build_path (NULL, engine->name);
+  engine_path = gtk_rc_find_module_in_path (fullname);
   
-  result = g_hash_table_lookup (engine_hash, name);
-
-  if (!result)
+  if (!engine_path)
     {
-       gchar *fullname;
-       gchar *engine_path;
-       GModule *library;
+      g_warning (_("Unable to locate loadable module in module_path: \"%s\","),
+                fullname);
       
-#ifndef __EMX__
-       fullname = g_module_build_path (NULL, name);
-#else
-       fullname = g_malloc (13);
-       gen_8_3_dll_name(name, fullname);
-#endif
-       engine_path = gtk_rc_find_module_in_path (fullname);
-#ifdef __EMX__
-       if (!engine_path)
-        {
-          /* try theme name without prefix '_' */
-          memmove(fullname, fullname + 1, strlen(fullname));
-          engine_path = gtk_rc_find_module_in_path (fullname);
-        }
-#endif
-
-       if (!engine_path)
-        {
-          g_warning (_("Unable to locate loadable module in module_path: \"%s\","),
-                     fullname);
-          
-          g_free (fullname);
-          return NULL;
-        }
-       g_free (fullname);
+      g_free (fullname);
+      return FALSE;
+    }
+    
+  g_free (fullname);
        
-       /* load the lib */
-
-       GTK_NOTE (MISC, g_message ("Loading Theme %s\n", engine_path));
+  /* load the lib */
+  
+  GTK_NOTE (MISC, g_message ("Loading Theme %s\n", engine_path));
        
-       library = g_module_open (engine_path, 0);
-       g_free(engine_path);
-       if (!library)
-        {
-          g_warning (g_module_error());
-          return NULL;
-        }
-       else
-        {
-           result = g_new (GtkThemeEngine, 1);
-           
-           result->refcount = 1;
-           result->name = g_strdup (name);
-           result->library = library;
-           result->plugins = NULL;
-           
-           /* extract symbols from the lib */
-           if (!g_module_symbol (library, "theme_init",
-                                 (gpointer *)&result->init) ||
-               !g_module_symbol (library, "theme_exit", 
-                                 (gpointer *)&result->exit) ||
-               !g_module_symbol (library, "theme_create_rc_style", 
-                                 (gpointer *)&result->create_rc_style))
-             {
-               g_warning (g_module_error());
-               g_free (result);
-               return NULL;
-             }
-           
-           /* call the theme's init (theme_init) function to let it */
-           /* setup anything it needs to set up. */
-           result->init((GtkThemeEngine *)result);
-           
-           g_hash_table_insert (engine_hash, result->name, result);
-        }
+  engine->library = g_module_open (engine_path, 0);
+  g_free(engine_path);
+  if (!engine->library)
+    {
+      g_warning (g_module_error());
+      return FALSE;
     }
-  else
-    result->refcount++;
-
-  return (GtkThemeEngine *)result;
-}
-
-void
-gtk_theme_engine_ref (GtkThemeEngine *engine)
-{
-  g_return_if_fail (engine != NULL);
   
-  engine->refcount++;
-}
-
-void
-gtk_theme_engine_unref (GtkThemeEngine *engine)
-{
-  GSList *tmp_list;
-
-  g_return_if_fail (engine != NULL);
-  g_return_if_fail (engine->refcount > 0);
-
-  engine->refcount--;
-
-  if (engine->refcount == 0)
+  /* extract symbols from the lib */
+  if (!g_module_symbol (engine->library, "theme_init",
+                       (gpointer *)&engine->init) ||
+      !g_module_symbol (engine->library, "theme_exit", 
+                       (gpointer *)&engine->exit) ||
+      !g_module_symbol (engine->library, "theme_create_rc_style", 
+                       (gpointer *)&engine->create_rc_style))
     {
-      engine->exit();
-
-      g_hash_table_remove (engine_hash, engine->name);
-
-      tmp_list = engine->plugins;
-      while (tmp_list)
-       {
-         GtkThemeEnginePlugin *plugin = tmp_list->data;
-         plugin->engine = NULL;
-
-         tmp_list = tmp_list->next;
-       }
-      g_slist_free (engine->plugins);
-      
+      g_warning (g_module_error());
       g_module_close (engine->library);
-      g_free (engine->name);
-      g_free (engine);
+      
+      return FALSE;
     }
-}
+           
+  /* call the theme's init (theme_init) function to let it */
+  /* setup anything it needs to set up. */
+  engine->init (module);
 
-GtkRcStyle *
-gtk_theme_engine_create_rc_style (GtkThemeEngine *engine)
-{
-  g_return_val_if_fail (engine != NULL, NULL);
-  
-  return engine->create_rc_style ();
+  return TRUE;
 }
 
 static void
-gtk_theme_engine_plugin_use (GTypePlugin *plugin)
+gtk_theme_engine_unload (GTypeModule *module)
 {
-  GtkThemeEnginePlugin *theme_plugin = GTK_THEME_ENGINE_PLUGIN (plugin);
+  GtkThemeEngine *engine = GTK_THEME_ENGINE (module);
 
-  if (theme_plugin->engine == NULL)
-    {
-      gtk_theme_engine_get (theme_plugin->engine_name);
-      if (!theme_plugin->engine)
-       {
-         g_warning ("An attempt to create an instance of a type from\n"
-                    "a previously loaded theme engine was made after the engine\n"
-                    "was unloaded, but the engine could not be reloaded or no longer\n"
-                    "implements the type. Bad things will happen.\n");
-       }
-    }
-  else
-    gtk_theme_engine_ref (theme_plugin->engine);
-}
+  engine->exit();
 
-static void
-gtk_theme_engine_plugin_unuse (GTypePlugin *plugin)
-{
-  GtkThemeEnginePlugin *theme_plugin = GTK_THEME_ENGINE_PLUGIN (plugin);
+  g_module_close (engine->library);
+  engine->library = NULL;
 
-  g_return_if_fail (theme_plugin->engine != NULL);
-  
-  gtk_theme_engine_unref (theme_plugin->engine);
+  engine->init = NULL;
+  engine->exit = NULL;
+  engine->create_rc_style = NULL;
 }
-                              
+
 static void
-gtk_theme_engine_plugin_complete_type_info (GTypePlugin     *plugin,
-                                           GType            g_type,
-                                           GTypeInfo       *info,
-                                           GTypeValueTable *value_table)
+gtk_theme_engine_class_init (GtkThemeEngineClass *class)
 {
-  GtkThemeEnginePlugin *theme_plugin = GTK_THEME_ENGINE_PLUGIN (plugin);
+  GTypeModuleClass *module_class = G_TYPE_MODULE_CLASS (class);
 
-  *info = theme_plugin->info;
+  module_class->load = gtk_theme_engine_load;
+  module_class->unload = gtk_theme_engine_unload;
 }
 
-/**
- * gtk_theme_engine_register_type:
- * @engine:      a #GtkThemeEngine
- * @parent_type: the type for the parent class
- * @type_name:   name for the type
- * @type_info:   type information structure
- * 
- * Looks up or registers a type that is implemented with a particular
- * theme engine. If a type with name @type_name is already registered,
- * the #GType identifier for the type is returned, otherwise the type
- * is newly registered, and the resulting #GType identifier returned.
- *
- * As long as any instances of the type exist, the a reference will be
- * held to the theme engine and the theme engine will not be unloaded.
- *
- * Return value: the type identifier for the class.
- **/
 GType
-gtk_theme_engine_register_type (GtkThemeEngine  *engine,
-                               GType            parent_type,
-                               const gchar     *type_name,
-                               const GTypeInfo *type_info)
+gtk_theme_engine_get_type (void)
 {
-  GtkThemeEnginePlugin *plugin;
-  GType type;
-  
-  g_return_val_if_fail (engine != NULL, 0);
-  g_return_val_if_fail (type_name != NULL, 0);
-  g_return_val_if_fail (type_info != NULL, 0);
+  static GType theme_engine_type = 0;
 
-  type = g_type_from_name (type_name);
-  if (type)
-    plugin = GTK_THEME_ENGINE_PLUGIN (g_type_get_plugin (type));
-  else
+  if (!theme_engine_type)
     {
-      plugin = g_object_new (GTK_TYPE_THEME_ENGINE_PLUGIN, NULL);
+      static const GTypeInfo theme_engine_info = {
+        sizeof (GtkThemeEngineClass),
+        NULL,           /* base_init */
+        NULL,           /* base_finalize */
+        (GClassInitFunc) gtk_theme_engine_class_init,
+        NULL,           /* class_finalize */
+        NULL,           /* class_data */
+        sizeof (GtkThemeEngine),
+        0,              /* n_preallocs */
+        NULL,           /* instance_init */
+      };
 
-      plugin->engine = NULL;
-      plugin->engine_name = NULL;
-      plugin->parent_type = parent_type;
-      plugin->type = g_type_register_dynamic (parent_type, type_name, G_TYPE_PLUGIN (plugin), 0);
+      theme_engine_type = g_type_register_static (G_TYPE_TYPE_MODULE, "GtkThemeEngine", &theme_engine_info, 0);
     }
   
-  if (plugin->engine)
-    {
-      if (plugin->engine != engine)
-       {
-         g_warning ("Two different theme engines tried to register '%s'.", type_name);
-         return 0;
-       }
+  return theme_engine_type;
+}
 
-      if (plugin->parent_type != parent_type)
-       {
-         g_warning ("Type '%s' recreated with different parent type.\n"
-                    "(was '%s', now '%s')", type_name,
-                    g_type_name (plugin->parent_type),
-                    g_type_name (parent_type));
-         return 0;
-       }
-    }
-  else
-    {
-      plugin->engine = engine;
-      if (plugin->engine_name)
-       g_free (plugin->engine_name);
+GtkThemeEngine*
+gtk_theme_engine_get (const gchar *name)
+{
+  GtkThemeEngine *result;
+  
+  if (!engine_hash)
+    engine_hash = g_hash_table_new (g_str_hash, g_str_equal);
 
-      plugin->engine_name = g_strdup (engine->name);
-      
-      plugin->info = *type_info;
+  /* get the library name for the theme
+   */
+  result = g_hash_table_lookup (engine_hash, name);
 
-      engine->plugins = g_slist_prepend (engine->plugins, plugin);
+  if (!result)
+    {
+      result = GTK_THEME_ENGINE (g_object_new (GTK_TYPE_THEME_ENGINE, NULL));
+      g_type_module_set_name (G_TYPE_MODULE (result), name);
+
+      g_hash_table_insert (engine_hash, result->name, result);
     }
 
-  return plugin->type;
+  if (!g_type_module_use (G_TYPE_MODULE (result)))
+    return NULL;
+
+  return result;
 }
 
+GtkRcStyle *
+gtk_theme_engine_create_rc_style (GtkThemeEngine *engine)
+{
+  g_return_val_if_fail (engine != NULL, NULL);
+
+  return engine->create_rc_style ();
+}
index 713bda7b6566addc661b97f32cd44659ee22870a..4c8b9a5550b8660f6c7195f8e429c5443c9717a3 100644 (file)
 #include <gtk/gtkstyle.h>
 #include <gtk/gtkwidget.h>
 
-
 #ifdef __cplusplus
 extern "C" {
 #endif /* __cplusplus */
 
-GtkThemeEngine * gtk_theme_engine_get             (const gchar     *name);
-void             gtk_theme_engine_ref             (GtkThemeEngine  *engine);
-void             gtk_theme_engine_unref           (GtkThemeEngine  *engine);
-GtkRcStyle     * gtk_theme_engine_create_rc_style (GtkThemeEngine  *engine);
-
-GType            gtk_theme_engine_register_type   (GtkThemeEngine  *engine,
-                                                  GType            parent_type,
-                                                  const gchar     *type_name,
-                                                  const GTypeInfo *type_info);
+#define GTK_TYPE_THEME_ENGINE             (gtk_theme_engine_get_type ())
+#define GTK_THEME_ENGINE(theme_engine)    (G_TYPE_CHECK_INSTANCE_CAST ((theme_engine), GTK_TYPE_THEME_ENGINE, GtkThemeEngine))
+#define GTK_IS_THEME_ENGINE(theme_engine) (G_TYPE_CHECK_INSTANCE_TYPE ((theme_engine), GTK_TYPE_THEME_ENGINE))
 
+GType           gtk_theme_engine_get_type        (void);
+GtkThemeEngine *gtk_theme_engine_get             (const gchar     *name);
+GtkRcStyle     *gtk_theme_engine_create_rc_style (GtkThemeEngine  *engine);
 
 #ifdef __cplusplus
 }
diff --git a/gtk/queryimmodules.c b/gtk/queryimmodules.c
new file mode 100644 (file)
index 0000000..ff4987b
--- /dev/null
@@ -0,0 +1,170 @@
+/* GTK+
+ * querymodules.c:
+ *
+ * Copyright (C) 2000 Red Hat Software
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#endif
+#include <gmodule.h>
+
+#include <errno.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdio.h>
+
+#ifdef G_OS_WIN32
+#define SOEXT ".dll"
+#else
+#define SOEXT ".so"
+#endif
+
+#include <pango/pango-utils.h>
+#include "gtk/gtkrc.h"
+#include "gtk/gtkimmodule.h"
+
+void
+print_escaped (const char *str)
+{
+  char *tmp = g_strescape (str, NULL);
+  printf ("\"%s\" ", tmp);
+  g_free (tmp);
+}
+
+gboolean
+query_module (const char *dir, const char *name)
+{
+  void          (*list)   (const GtkIMContextInfo ***contexts,
+                          guint                    *n_contexts);
+  void          (*init)   (GTypeModule              *type_module);
+  void          (*exit)   (void);
+  GtkIMContext *(*create) (const gchar             *context_id);
+
+  GModule *module;
+  gchar *path;
+  gboolean error = FALSE;
+
+  if (name[0] == G_DIR_SEPARATOR)
+    path = g_strdup (name);
+  else
+    path = g_strconcat (dir, G_DIR_SEPARATOR_S, name, NULL);
+  
+  module = g_module_open (path, 0);
+
+  if (!module)
+    {
+      fprintf(stderr, "Cannot load module %s: %s\n", path, g_module_error());
+      error = TRUE;
+    }
+         
+  if (module &&
+      g_module_symbol (module, "im_module_list", (gpointer)&list) &&
+      g_module_symbol (module, "im_module_init", (gpointer)&init) &&
+      g_module_symbol (module, "im_module_exit", (gpointer)&exit) &&
+      g_module_symbol (module, "im_module_create", (gpointer)&create))
+    {
+      const GtkIMContextInfo **contexts;
+      guint n_contexts;
+      int i;
+
+      print_escaped (path);
+      fputs ("\n", stdout);
+
+      (*list) (&contexts, &n_contexts);
+
+      for (i=0; i<n_contexts; i++)
+       {
+         print_escaped (contexts[i]->context_id);
+         print_escaped (contexts[i]->context_name);
+         print_escaped (contexts[i]->domain);
+         print_escaped (contexts[i]->domain_dirname);
+         print_escaped (contexts[i]->default_locales);
+         fputs ("\n", stdout);
+       }
+      fputs ("\n", stdout);
+    }
+  else
+    {
+      fprintf (stderr, "%s does not export GTK+ IM module API: %s\n", path,
+              g_module_error());
+      error = TRUE;
+    }
+
+  g_free (path);
+  if (module)
+    g_module_close (module);
+
+  return error;
+}                     
+
+int main (int argc, char **argv)
+{
+  char cwd[PATH_MAX];
+  int i;
+  char *path;
+  gboolean error = FALSE;
+
+  printf ("# GTK+ Input Method Modules file\n"
+         "# Automatically generated file, do not edit\n"
+         "#\n");
+
+  if (argc == 1)               /* No arguments given */
+    {
+      char **dirs;
+      int i;
+
+      path = gtk_rc_get_im_module_path ();
+
+      printf ("# ModulesPath = %s\n#\n", path);
+
+      dirs = pango_split_file_list (path);
+
+      for (i=0; dirs[i]; i++)
+       {
+         DIR *dir = opendir (dirs[i]);
+         if (dir)
+           {
+             struct dirent *dent;
+
+             while ((dent = readdir (dir)))
+               {
+                 int len = strlen (dent->d_name);
+                 if (len > 3 && strcmp (dent->d_name + len - strlen (SOEXT), SOEXT) == 0)
+                   error |= query_module (dirs[i], dent->d_name);
+               }
+             
+             closedir (dir);
+           }
+       }
+    }
+  else
+    {
+      getcwd (cwd, PATH_MAX);
+      
+      for (i=1; i<argc; i++)
+       error |= query_module (cwd, argv[i]);
+    }
+  
+  return error ? 1 : 0;
+}
index cf36663f286dc4835c4dbee5ddc0285e75c96744..fd1795f2f6d56d4fe0c0cc7658d2436b9098ec0f 100644 (file)
@@ -9229,11 +9229,14 @@ create_main_window (void)
   gtk_widget_show_all (window);
 }
 
-void
-pixbuf_init ()
+static void
+test_init ()
 {
   if (file_exists ("../gdk-pixbuf/.libs/libpixbufloader-pnm.so"))
-    putenv ("GDK_PIXBUF_MODULEDIR=../gdk-pixbuf/.libs");
+    {
+      putenv ("GDK_PIXBUF_MODULEDIR=../gdk-pixbuf/.libs");
+      putenv ("GTK_IM_MODULE_FILE=./gtk.immodules");
+    }
 }
 
 int
@@ -9243,7 +9246,7 @@ main (int argc, char *argv[])
 
   srand (time (NULL));
 
-  pixbuf_init ();
+  test_init ();
   gtk_set_locale ();
 
   /* Check to see if we are being run from the correct
index 5424dc0f7f14e6ba740cdad214a2a5658ba8fcc4..279535aecdf8b1323cc0a5a79b836a6f03af8543 100644 (file)
@@ -1922,13 +1922,32 @@ create_view (Buffer *buffer)
   return view;
 }
 
+static gboolean
+file_exists (const char *filename)
+{
+  struct stat statbuf;
+
+  return stat (filename, &statbuf) == 0;
+}
+void
+test_init ()
+{
+  if (file_exists ("../gdk-pixbuf/.libs/libpixbufloader-pnm.so"))
+    {
+      putenv ("GDK_PIXBUF_MODULEDIR=../gdk-pixbuf/.libs");
+      putenv ("GTK_IM_MODULE_FILE=./gtk.immodules");
+    }
+}
+
 int
 main (int argc, char** argv)
 {
   Buffer *buffer;
   View *view;
   int i;
-  
+
+  test_init ();
+  gtk_set_locale ();
   gtk_init (&argc, &argv);
   
   buffer = create_buffer ();
index cf36663f286dc4835c4dbee5ddc0285e75c96744..fd1795f2f6d56d4fe0c0cc7658d2436b9098ec0f 100644 (file)
@@ -9229,11 +9229,14 @@ create_main_window (void)
   gtk_widget_show_all (window);
 }
 
-void
-pixbuf_init ()
+static void
+test_init ()
 {
   if (file_exists ("../gdk-pixbuf/.libs/libpixbufloader-pnm.so"))
-    putenv ("GDK_PIXBUF_MODULEDIR=../gdk-pixbuf/.libs");
+    {
+      putenv ("GDK_PIXBUF_MODULEDIR=../gdk-pixbuf/.libs");
+      putenv ("GTK_IM_MODULE_FILE=./gtk.immodules");
+    }
 }
 
 int
@@ -9243,7 +9246,7 @@ main (int argc, char *argv[])
 
   srand (time (NULL));
 
-  pixbuf_init ();
+  test_init ();
   gtk_set_locale ();
 
   /* Check to see if we are being run from the correct
index 5424dc0f7f14e6ba740cdad214a2a5658ba8fcc4..279535aecdf8b1323cc0a5a79b836a6f03af8543 100644 (file)
@@ -1922,13 +1922,32 @@ create_view (Buffer *buffer)
   return view;
 }
 
+static gboolean
+file_exists (const char *filename)
+{
+  struct stat statbuf;
+
+  return stat (filename, &statbuf) == 0;
+}
+void
+test_init ()
+{
+  if (file_exists ("../gdk-pixbuf/.libs/libpixbufloader-pnm.so"))
+    {
+      putenv ("GDK_PIXBUF_MODULEDIR=../gdk-pixbuf/.libs");
+      putenv ("GTK_IM_MODULE_FILE=./gtk.immodules");
+    }
+}
+
 int
 main (int argc, char** argv)
 {
   Buffer *buffer;
   View *view;
   int i;
-  
+
+  test_init ();
+  gtk_set_locale ();
   gtk_init (&argc, &argv);
   
   buffer = create_buffer ();